Databases

FTL has support for Postgresql and MySQL databases, including support for automatic provisioning and migrations.

The process for declaring a database differs by language.

To use a database in go you must create a struct that implements either the ftl.MySQLDatabaseConfig or ftl.PostgresDatabaseConfig interface. Generally this will involve creating a struct that embeds the ftl.DefaultMySQLDatabaseConfig or ftl.DefaultPostgresDatabaseConfig struct and then implementing the Name() string method.

You can then use the ftl.DatabaseHandle type to access the database by injecting it into an FTL verb. An example for MySQL is shown below:

package mysql

import (
	"context"
	"database/sql"

	"github.com/block/ftl/go-runtime/ftl" // Import the FTL SDK.
)

type TestDatasourceConfig struct {
	ftl.DefaultMySQLDatabaseConfig
}

func (TestDatasourceConfig) Name() string { return "testdb" }

//ftl:verb export
func Query(ctx context.Context, db ftl.DatabaseHandle[TestDatasourceConfig]) ([]string, error) {
	var database *sql.DB = db.Get(ctx) // Get the database connection.
	// The following code is standard golang SQL code, it has nothing FTL specific.
	rows, err := database.QueryContext(ctx, "SELECT data FROM requests")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []string
	for rows.Next() {
		var i string
		if err := rows.Scan(
			&i,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

To declare a datasource in Kotlin you must create an application.properties file in the src/main/resources directory. Datasources currently leverage the Quarkus Database extension, and so databases are configured using Quarkus config. To define a MySQL database using the Quarkus Hibernate extension you would do the following:

quarkus.datasource.testdb.db-kind=mysql
quarkus.hibernate-orm.datasource=testdb

To use this in your FTL code you can then just use Hibernate directly or using Panache.

Note that this will likely change significantly in future once FTL has SQL Verbs.

To declare a datasource in Java you must create an application.properties file in the src/main/resources directory. Datasources currently leverage the Quarkus Database extension, and so databases are configured using Quarkus config. To define a MySQL database using the Quarkus Hibernate extension you would do the following:

quarkus.datasource.testdb.db-kind=mysql
quarkus.hibernate-orm.datasource=testdb

To use this in your FTL code you can then just use Hibernate directly or using Panache.

Note that this will likely change significantly in future once FTL has SQL Verbs.

An example showing DB usage with Pachance is shown below:

package xyz.block.ftl.java.test.database;

import java.util.List;
import java.util.Map;

import jakarta.transaction.Transactional;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

import xyz.block.ftl.Verb;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

public class Database {
    
    @Verb
    @Transactional
    public List<Request> query() {
        List<Request> requests = Request.listAll();
        return requests;
    }
}


@Entity
@Table(name = "requests")
public class Request extends PanacheEntity {
    public String data;
    
}

Provisioning

FTL includes support for automatically provisioning databases. The actual backing implementation is extensible, and presently we include support for both local development provisioning using docker, and cloud formations based provisioning for AWS deployments. When using ftl dev a docker container will automatically be spun up for each datasource that has been defined, and FTL will automatically handle configuration. The same applies when deploying to an AWS cluster with cloud formations provisioning setup.

Migrations

FTL includes support for automatically running migrations on databases. This is provided by dbmate.

To create migrations you can use the ftl new-sql-migration command. This will create new migration files, and initialize the required directory structure if it does not exist. The format of the command is ftl new-sql-migration <module>.<datasource> <migration-name>.

The module name can be omitted if the current working directory only contains a single module.

E.g. to create a new migration called init for the testdb datasource in the mysql module you would run ftl new-sql-migration mysql.testdb init.

When the modules are provisioned FTL will automatically run these migrations for you.