Use Turso DB with Strapi 4

Turso is a SQLite database in the cloud called LibSQL. It's based on SQLite, and is compatiable with SQLite, but it can be accessed over the internet, unlike SQLite, which always requires a file in the file system.

While it is possible to use SQLite in production if you store the database file in a persistent volume, using Turso might be useful in some cases, as you can view the data in the browser and easily access it from your computer as well as on your server.

Strapi uses the Knex query builder to communicate with the database, and Knex does not support LibSQL out of the box. You also cannot provide Strapi with a custom Knex client, so we need to patch the Strapi source code.

This guide uses pnpm to do the patching, but it should also work with Yarn or patch-package for npm.

Step-by-step guide

Bn in the directory of your Strapi app. I used a newly created Strapi4 app for this guide, but it should work with your existing project.

With pnpm you:

Create a patch with pnpm patch @strapi/[email protected] --edit-dir strapi-db-patch

Edit the file you're patching which will be in strapi-db-patch/dist/index.js

You need to add this to the top of the file

const Client_SQLite3 = require("knex/lib/dialects/sqlite3");
class Client_Libsql extends Client_SQLite3 {
  _driver() {
    return require("@libsql/sqlite3");
  }
}
Object.assign(Client_Libsql.prototype, {
  dialect: "libsql",
  driverName: "libsql",
});

And also add a near copy of the existing SqliteDialect like this:

class LibsqlDialect extends SqliteDialect {
  schemaInspector;
  constructor(db) {
    super(db);
    this.client = "libsql";
  }
  configure() {}
}

Then edit the getDialectClass and getDialectName functions like this:

const getDialectClass = (client) => {
  switch (client) {
    case "postgres":
      return PostgresDialect;
    case "mysql":
      return MysqlDialect;
    case "sqlite":
      return SqliteDialect;
    case "libsql":
      return LibsqlDialect;
    default:
      throw new Error(`Unknown dialect ${client}`);
  }
};
const getDialectName = (client) => {
  switch (client) {
    case "postgres":
      return "postgres";
    case "libsql":
      return "libsql";
    case "mysql":
    case "mysql2":
      return "mysql";
    case "sqlite":
    case "sqlite-legacy":
      return "sqlite";
    default:
      throw new Error(`Unknown dialect ${client}`);
  }
};

Add this one line to applySearch above case "sqlite":

// ...
case "libsql":
case "sqlite": {
// ...

Finally, edit createConnection to this:

const createConnection = (config) => {
  const knexConfig = { ...config };
  if (knexConfig.client === "libsql") {
    knexConfig.client = Client_Libsql;
  }
  if (knexConfig.client === "sqlite") {
    const sqlitePackageName = getSqlitePackageName();
    knexConfig.client = clientMap[sqlitePackageName];
  }
  return knex__default.default(knexConfig);
};

Now you store the patch to your code with pnpm patch-commit 'strapi-db-patch'

Remember to install this libsql package: pnpm i @libsql/sqlite3

Then edit your standard config/database.js with something like this:

const connections = {
// ...
libsql: {
      connection: {
        filename:
          "wss://my-strapi-db.turso.io?authToken=my_turso_auth_token",
      },
      useNullAsDefault: true,
    },

I did not get it to work with the libsql:// or https:// protocols, because the connection timed out or something. So you must use wss://

Update the .env to use the libsql connection DATABASE_CLIENT=libsql

You can now run pnpm develop and see the Turso database be filled up with Strapi tables.

My packages at the time of writing were:

"@libsql/sqlite3": "^0.3.1",
"@strapi/strapi": "4.25.9",
"better-sqlite3": "8.6.0",
"knex": "^3.1.0",