How to Add a Database to Your App
Most apps need somewhere to keep their data. On Chajio Cloud, a managed database sits right next to your app, runs as a primary with a live standby copy, and hands its connection details to your app for you. This guide covers creating one, connecting it, and using it from Node.js and Python.
On this page
Which plans include a database
The Growth, Business and Pro plans include a dedicated managed database. The Free plan doesn’t, but your app can still use a database hosted elsewhere: add its connection string as an environment variable, as described at the end of this guide.
Two database engines are available, with MySQL coming soon:
- PostgreSQL: the usual choice for new apps. Powerful SQL, JSON support and full-text search, and supported by practically every framework.
- MariaDB: a drop-in alternative to MySQL. Apps and libraries written for MySQL work with it unchanged, which makes it the natural home for Laravel and WordPress-style apps.
Step 1: Create the database
Open your project, go to the Databases tab and click New database:
- Name
- Something descriptive, like orders-db.
- Engine
- PostgreSQL or MariaDB.
- Resources
- Memory and storage for the database, from what your project has available. Leave some room to grow.
- Replicas
- Set by your plan. With two, a primary handles reads and writes, and a standby copy on a separate machine takes over automatically if the primary fails.
- Connect your app
- The environment variable your app reads the connection string from, usually DATABASE_URL. Leave it empty to connect your app yourself.
Click Create PostgreSQL database (or MariaDB). It takes two to five minutes to set up, and the card shows its progress. When it’s ready, the variable you chose appears on your app’s Environment tab, locked because the platform manages it, and your app restarts to pick it up. If you left the name empty, you can connect it later from the database’s card, or rename or remove the variable the same way.
Step 2: Use it from your app
The connection string looks like one of these:
postgresql://user:password@host:5432/database (PostgreSQL)
mysql://user:password@host:3306/database (MariaDB)Most libraries accept it as it is. If a tool wants the host, port, user and password as separate fields, open the database’s card and reveal its credentials.
Node.js
const { Pool } = require("pg");
const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 5 });
const { rows } = await pool.query("SELECT now()");const mysql = require("mysql2/promise");
const pool = mysql.createPool(process.env.DATABASE_URL);With Prisma, point the datasource at the variable, using provider = "postgresql" or provider = "mysql" for MariaDB:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}Python
Django reads the variable through dj-database-url, as set up in the Python guide:
import dj_database_url
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}SQLAlchemy (and Flask-SQLAlchemy, SQLModel and FastAPI apps built on them) needs the driver in the URL’s scheme, so adjust it once when you read it:
import os
from sqlalchemy import create_engine
url = os.environ["DATABASE_URL"]
url = url.replace("postgresql://", "postgresql+psycopg://", 1) # PostgreSQL, with psycopg 3
# url = url.replace("mysql://", "mysql+pymysql://", 1) # MariaDB, with PyMySQL
engine = create_engine(url, pool_size=5, pool_pre_ping=True)Add the driver to requirements.txt: psycopg[binary] for PostgreSQL, PyMySQL or mysqlclient for MariaDB.
Running migrations
Your database is private: only your app can reach it, not the internet. That keeps it safe, and it means migrations should run from your app, as it starts:
# Prisma (package.json)
"start": "prisma migrate deploy && node dist/index.js"
# Django: already part of the default start command, or in your Procfile
web: python manage.py migrate && gunicorn yourproject.wsgi
# Alembic (Procfile)
web: alembic upgrade head && uvicorn main:app --host 0.0.0.0 --port $PORTTwo copies start at once
Your app runs as two copies, and both run the start command. Prisma takes a lock, so only one copy migrates while the other waits. With other tools both may try at once: the second usually fails, restarts, and finds the work already done. That recovers on its own, but it’s one more reason to write migrations that are safe to run twice, for example with CREATE TABLE IF NOT EXISTS.
Good habits
- Keep connection pools small. Each copy of your app opens its own pool, so a pool of five means ten connections. Five is plenty for most apps.
- Never hard-code the connection string. Always read it from the environment variable, so it stays out of your code and your Git history.
- Check the backup status on the database page, which shows whether nightly backups are on for your plan.
- Deleting a database deletes its data, permanently. The dashboard asks you to confirm.
Using a database hosted elsewhere
On the Free plan, or if your data already lives with another provider, add its connection string on the Environment tab yourself, for example as DATABASE_URL, and click Save & restart.
Which outside services your app can reach
For security, apps connect out to the internet on three ports only: 80 and 443 (websites and HTTPS APIs) and 5432 (PostgreSQL). An external PostgreSQL database works. External MySQL (port 3306), Redis or MongoDB servers can’t be reached directly; use a managed database here, or a provider that offers an HTTPS API.
Common problems
The app can’t connect: DATABASE_URL is undefined
The database was created without an app variable, or with a different name. Set it from the database’s card, and check your code reads the same name.
SQLAlchemy: “Can’t load plugin: sqlalchemy.dialects:postgres”
The URL’s scheme needs adjusting for SQLAlchemy, as shown above. Replace postgresql:// with postgresql+psycopg://.
“Too many connections”
Your pools are too big for the database’s size. Lower the pool size in your app; remember each copy of your app has its own.
You want to open the database in a desktop tool
The database only accepts connections from your app, which is what keeps it off the internet. For one-off access, run a query from your app, or contact support.
Learning path
Deploy your first app
- 1
Deploy your app
- 2
- 3
- 4
Keep reading
How to Deploy a Node.js App (Express, Fastify or NestJS)
Deploy a Node.js API or server from GitHub, JavaScript or TypeScript. The two lines of code every app needs, choosing a Node version, and shutting down cleanly for seamless updates.
How to Deploy a Python App (Flask, FastAPI or Django)
Get a Flask, FastAPI or Django app live from GitHub. What to put in your repository, how to tell the platform how to start your app, and the Django settings that trip people up.
How to Deploy a Next.js App
Deploy a full Next.js app, with server rendering, API routes and middleware, straight from GitHub. Covers public and server-side variables, databases and connecting your domain.
Deployment Failed? How to Find and Fix the Cause
Every failed deployment tells you which stage broke and why. How to read it, and the fixes for the failures we see most: missing start commands, port mix-ups, health checks and memory.
Ready to deploy?
Start on the Free plan: your first month is on us, and every app runs two copies for high availability.