Connect your app to a database

Take the connection string from the Databases page and turn it into working queries — in Node, Python, and beyond.

You made a database — now let's make your code talk to it. The pattern is the same in every language: store the connection string as an environment variable, read it at startup, hand it to a database driver. Do that once and the queries are just ordinary SQL.

At a glance
You need A managed database of any type (Add a database) and an app server running your language
Plan Any
Time About twenty minutes

The one rule: the string lives in .env

⚠️ Heads up: Never hard-code the connection string.

Copy it from the Databases page and store it as DATABASE_URL in your server's .env file — see Environment variables and secrets for how .env works on Falix. Your code reads it from the environment: process.env.DATABASE_URL in Node, os.environ["DATABASE_URL"] in Python. If you ever rotate the password, you paste the new string into .env and nothing else changes.

Install the driver

A driver is the library that speaks the database's wire protocol. Add it the easy way: open the Packages page in your server menu, type the package name into the Install package panel, press Install, then restart the server so your app loads it. For MySQL that's mysql2 (Node) or PyMySQL (Python).

Node + MySQL (mysql2)

With mysql2 installed, index.js:

const mysql = require('mysql2/promise');

async function main() {
  const db = await mysql.createConnection(process.env.DATABASE_URL);

  await db.execute(`
    CREATE TABLE IF NOT EXISTS scores (
      user_id VARCHAR(32) PRIMARY KEY,
      points  INT NOT NULL DEFAULT 0
    )
  `);

  await db.execute(
    `INSERT INTO scores (user_id, points) VALUES (?, ?)
     ON DUPLICATE KEY UPDATE points = points + VALUES(points)`,
    ['alice', 5]
  );

  const [rows] = await db.execute('SELECT * FROM scores');
  console.log(rows);

  await db.end();
}

main().catch(console.error);

createConnection takes the whole URL, so there's nothing to parse. CREATE TABLE IF NOT EXISTS makes the table on first run and does nothing afterward. The ON DUPLICATE KEY UPDATE line is an upsert — insert a row, or add to it if that user_id already exists — exactly the shape a bot's scoreboard needs.

Python + MySQL (PyMySQL)

PyMySQL doesn't take a URL directly, so split it apart with urlparse. app.py:

import os
from urllib.parse import urlparse
import pymysql

url = urlparse(os.environ["DATABASE_URL"])
conn = pymysql.connect(
    host=url.hostname,
    port=url.port,
    user=url.username,
    password=url.password,
    database=url.path.lstrip("/"),
)

with conn.cursor() as cur:
    cur.execute(
        "CREATE TABLE IF NOT EXISTS scores ("
        " user_id VARCHAR(32) PRIMARY KEY,"
        " points INT NOT NULL DEFAULT 0)"
    )
    cur.execute(
        "INSERT INTO scores (user_id, points) VALUES (%s, %s)"
        " ON DUPLICATE KEY UPDATE points = points + VALUES(points)",
        ("alice", 5),
    )
    conn.commit()
    cur.execute("SELECT * FROM scores")
    print(cur.fetchall(), flush=True)

conn.close()

urlparse pulls the host, port, user, password, and database name out of the same string you copied from the panel. flush=True makes the output show up in the console right away.

💡 Tip: Don't forget conn.commit() — without it your inserts roll back when the connection closes.

PostgreSQL and MongoDB — same pattern, different driver

🎯 Good to know: Nothing above changes except the string and the library.

Use the connection string the panel gives you for that database type, keep it in DATABASE_URL, and reach for the standard driver:

  • PostgreSQL: pg in Node, psycopg in Python. Both accept the postgresql://… string directly — for example in Node:

    const { Client } = require('pg');
    const db = new Client({ connectionString: process.env.DATABASE_URL });
    await db.connect();
  • MongoDB: the mongodb driver in Node (or pymongo in Python). It takes the whole mongodb://…?authSource=… string as-is:

    const { MongoClient } = require('mongodb');
    const client = new MongoClient(process.env.DATABASE_URL);
    await client.connect();

From there the queries are whatever that driver documents — the Falix-specific part is done once you're connected. Install any of these from the Packages page just like mysql2.

Long-running apps: use a pool

The examples above open one connection, do their work, and close it — exactly right for a script that runs a task and exits. A bot or web server is different: it stays up for hours, and a single connection left open can quietly drop (an idle timeout, a network blip). After that, every query throws until something reconnects.

The fix is a connection pool — a small set of connections the driver keeps ready, handing one out per query and replacing any that die. In most drivers it's a small change:

  • Node (mysql2): swap createConnection for createPool, then call pool.execute(...) per query — same API, and no manual end().
  • Node (pg): use new Pool(...) in place of new Client(...).
  • Python (PyMySQL): it has no built-in pool — keep one connection open for the app's life and reconnect if a query fails, or let a layer like SQLAlchemy pool for you.
  • MongoDB (mongodb / pymongo): the client already pools internally — create one client when the app starts and reuse it everywhere; never open one per request.

Open the pool (or client) once at startup, reuse it for the whole run, and let it manage the connections for you.

Verify it works

Start the server and watch the Console. The Node example prints the rows it just wrote; the Python one prints the fetched tuples. See your inserted row and the round trip works — code to database and back. For MySQL you can also open phpMyAdmin from the Databases page and see the scores table sitting there.

Troubleshooting

  • Access denied / authentication failed — the username or password in your string is stale. Rotate the password on the Databases page, copy the fresh connection string, and paste it back into .env.
  • getaddrinfo / can't resolve host — you're not using the exact host from the page (a common slip is using localhost). Copy the host value from the database exactly as shown.
  • Cannot find module / ModuleNotFoundError — the driver isn't installed, or you didn't restart after installing. Install it on the Packages page and restart. See My app won't start.
  • My data vanished after a reinstall — it didn't, if it's in a managed database. Managed databases survive reinstalls and application switches; that's the whole point. Double-check you're connecting to the same database and not writing to a local file.

Next steps

Was this guide helpful?