Connect to a Live Database
On Pro, Sqemo can read a real PostgreSQL or MySQL database — to import its schema into an ERD, or to check whether the database has drifted from the ERD you treat as the source of truth. Everything runs locally (or in your CI job) through sqemo-mcp; your database credentials are never sent to Sqemo.
This guide walks the whole flow end to end. Follow it top to bottom the first time.
What you need
- Node.js 22+ (
node --versionto check). - A Pro Sqemo account (or a Team workspace member). On the Free plan the database commands stop with an upgrade notice before connecting.
- A database to check — or none at all: see the Docker option below to spin one up in a couple of minutes.
Step 1 — Sign in from the terminal
The database commands need you signed in. Sign in once:
npx sqemo-mcp login
# Email: you@example.com
# Password: ••••••••
This stores a refresh token in ~/.erdmaker/credentials.json (your password
itself is never stored). npx sqemo-mcp logout removes it.
Signed up with Google or GitHub? Set a password first
The terminal sign-in uses email + password. If you created your Sqemo
account by clicking Continue with Google / GitHub, your account has no
password yet — so login (and the CI env variables) can’t authenticate.
Add one once; this does not remove social login, it just adds a second
way in:
- Open the app at app.sqemo.com and open the sign-in dialog.
- Click Forgot your password? / Reset.
- Enter the same email your Google/GitHub account uses, and send the reset link.
- Open the link from your inbox and set a password.
- Now
npx sqemo-mcp loginworks with that email and password. You can still sign in with Google/GitHub in the app as before.
Longer term we plan to add CI-friendly API keys so social-login users won’t need a password at all — for now, this one-time setup is the way in.
Step 2 — Get your ERD as a baseline
Drift is ERD vs database, so you need the ERD side. Two ways:
- Server ERD (saved to your account): use
--erd <id>. The id comes from thelist_erdsMCP tool, or the app URL when the ERD is open. - Local project (lives only in your browser): export it to a file first.
In the app: toolbar → Export → Download project. You get a
<name>.erd.jsonfile (usually in your Downloads folder). Commit this file to your repo if you’ll run the check in CI — it becomes your schema’s source of truth.
Step 3 — Run the drift check
Point lint at your ERD and your database:
# local project file
npx sqemo-mcp lint "Online Shop Example.erd.json" --db "mysql://user:pass@host:3306/dbname"
# a server ERD instead of a file
npx sqemo-mcp lint --erd <erd-id> --db "postgresql://user:pass@host:5432/dbname"
Connection URL formats:
PostgreSQL: postgresql://user:pass@host:5432/dbname
MySQL: mysql://user:pass@host:3306/dbname
Which databases are supported?
The rule of thumb: a live --db connection works with PostgreSQL and MySQL
(including MariaDB) only. Every other dialect is still supported for
exporting/importing SQL, and you can drift-check it through the
--schema dump path — you just can’t connect
to it live.
| Database | ERD export/import | Live --db | Dump --schema --dialect |
|---|---|---|---|
| PostgreSQL | ✓ | ✓ | ✓ postgres |
| MySQL / MariaDB | ✓ | ✓ (mysql://) | ✓ mysql |
| Oracle | ✓ | — | ✓* oracle |
| SQL Server | ✓ | — | ✓* sqlserver |
| SQLite | ✓ | — | ✓* sqlite |
| H2 | ✓ | — | ✓* h2 |
| CUBRID | ✓ | — | ✓* cubrid |
* Parser exists but that dialect isn’t in the officially tested set, so results may vary with the dump’s exact format.
Why only PostgreSQL and MySQL connect live: both ship pure-JavaScript
drivers (nothing to install beyond npx) and share the standard
information_schema, so one introspection path covers both. The others each
need a different driver and catalog — Oracle wants its Instant Client and its
own data dictionary, SQLite is a file rather than a server, H2 is
Java/JDBC-only, and so on — so for now they go through the dump path.
MariaDB note: connect with the mysql:// scheme (not mariadb://, which
isn’t recognised) since it speaks the MySQL protocol; use --dialect mysql
for dump mode. MariaDB-specific column types may surface as warnings (which
pass by default) rather than errors.
Useful options:
--db-schema <name>— schema to read (PostgreSQL defaults topublic; MySQL reads the database in the URL).--ignore "flyway_*"— skip tables that live in the DB but not the ERD (migration-history, audit tables). Repeatable.--strict— treat type/representation differences (normally warnings) as failures too.--schema dump.sql --dialect postgres— compare against apg_dump -sfile instead of connecting, so no database URL is needed at all.
Step 4 — Read the result
The command’s exit code is the answer (echo $LASTEXITCODE on
PowerShell, echo $? on bash):
| Exit | Meaning |
|---|---|
| 0 | ERD and database match. |
| 1 | Drift found. Each item is listed, e.g. [missing_column] CUST.EMAIL, [missing_table] ORDER_ITEM, plus a summary line. |
| 2 | Couldn’t compare yet — bad connection, wrong/empty schema, not signed in, Free plan, or a usage error. Passwords in the URL are masked as :****@ in messages. |
Note that an empty database (zero tables in the schema) reports exit 2, not “everything is missing” — that almost always means the schema name or database is pointed at the wrong place, so the tool asks you to check rather than drowning you in false positives.
No database yet? Use Docker
You don’t need a hosted database to try this. Spin one up, load your ERD’s schema into it, and check:
# 1) start a throwaway MySQL
docker run -d --name sqemo-my -e MYSQL_ROOT_PASSWORD=pw -e MYSQL_DATABASE=app -p 13306:3306 mysql:8
# wait ~30s for it to initialise
# 2) turn your ERD into SQL and load it
npx sqemo-mcp export "Online Shop Example.erd.json" --format sql --dialect mysql > shop.sql
docker exec -i sqemo-my mysql -uroot -ppw app < shop.sql
# 3) check — matches, so exit 0
npx sqemo-mcp lint "Online Shop Example.erd.json" --db "mysql://root:pw@localhost:13306/app"
# 4) change the DB, then re-check — now exit 1 with the difference
docker exec sqemo-my mysql -uroot -ppw app -e "ALTER TABLE CUST DROP COLUMN EMAIL;"
npx sqemo-mcp lint "Online Shop Example.erd.json" --db "mysql://root:pw@localhost:13306/app"
# 5) clean up
docker rm -f sqemo-my
Swap mysql:8 / the mysql:// URL for postgres:16 /
postgresql://postgres:pw@localhost:15432/app (port -p 15432:5432) to try
PostgreSQL. Tip: match --dialect to the database — a schema exported for the
wrong engine may use types the other one doesn’t have.
Where do the database credentials live?
Sqemo never stores them — you supply the URL at run time. Keep it out of the ERD file and out of version control:
- Local, occasional runs: an environment variable or a
.envfile that’s in.gitignore. Avoid typing the password straight on the command line (it lands in your shell history). - MCP client (agent): put it in the client’s server config as an
envvalue (e.g. Claude Desktop’sclaude_desktop_config.json), which stays on your machine. - CI: your platform’s secret store — GitHub Actions Secrets, GitLab CI variables, etc. Never in the workflow file.
Strongly recommended: give the tool a read-only database account.
It only queries information_schema / the catalog, so a read-only account
loses nothing — and if the secret ever leaks, the blast radius is limited to
schema structure, not your data.
Put it in CI (GitHub Actions, step by step)
The point of drift checking is catching it automatically — every push, every pull request — instead of remembering to run it by hand. Here’s the whole setup from scratch, no prior GitHub Actions experience assumed.
1. Commit your ERD to the repo
Export the project (toolbar → Export → Download project) and put the
.erd.json in your repository, e.g. erd/app.erd.json, then commit and push
it. This file is now your schema’s source of truth — changes to it go through
pull-request review like any code.
2. Add the secrets
Secrets are encrypted values GitHub injects into the job; they never appear in your code or logs. In your repository on GitHub:
Settings → Secrets and variables → Actions → New repository secret. Add three:
| Name | Value |
|---|---|
DATABASE_URL | your connection string, e.g. mysql://user:pass@host:3306/db (a read-only account is best) |
SQEMO_EMAIL | your Sqemo Pro account email |
SQEMO_PASSWORD | that account’s password (set one first if you signed up with Google/GitHub — see Step 1) |
3. Add the workflow file
Create .github/workflows/schema-drift.yml in your repo with this content:
name: Schema drift
on:
push:
paths: ["erd/**"] # runs when the ERD changes
pull_request: # and on every PR, so drift blocks the merge
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- run: npx sqemo-mcp lint erd/app.erd.json --db "$DATABASE_URL" --ignore "flyway_*"
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SQEMO_EMAIL: ${{ secrets.SQEMO_EMAIL }}
SQEMO_PASSWORD: ${{ secrets.SQEMO_PASSWORD }}
${{ secrets.NAME }}pulls in the values you added in Step 2 — never paste the real credentials into this file.on:decides when it runs. As written: whenever the ERD changes on a push, and on every pull request. Changepathsor addbranchesto taste.SQEMO_EMAIL/SQEMO_PASSWORDsign in just for that job — nologinstep or stored token needed.
4. Push, and it runs
Commit the workflow file and push. From now on GitHub runs the check
automatically on the events you listed — you don’t trigger it manually.
Push a change under erd/, or open a PR, and the job starts on its own.
Optional: no database credentials in CI
If you’d rather not give CI a live database URL, have a job inside your
network run pg_dump -s and compare against the dump file instead. No
DATABASE_URL, and the --db becomes --schema:
- run: npx sqemo-mcp lint erd/app.erd.json --schema schema.sql --dialect postgres
env:
SQEMO_EMAIL: ${{ secrets.SQEMO_EMAIL }}
SQEMO_PASSWORD: ${{ secrets.SQEMO_PASSWORD }}
Optional: check against a server ERD instead of the file
--erd <id> uses an ERD saved in your Sqemo account as the baseline, so you
skip committing a file. The CI account must have read access to it.
- run: npx sqemo-mcp lint --erd <erd-id> --db "$DATABASE_URL"
Trade-off worth knowing: a committed .erd.json is pinned and reviewed —
it changes only through a PR, and old commits re-check against their own
baseline. A server ERD is the current, mutable standard, so if someone
edits it in the app, the CI result can change with no code change. For
reproducible PR gating the committed file is the safer default; use --erd
when your team deliberately treats the server ERD as the single live standard.
Where do the results show up?
In GitHub, not in Sqemo. Sqemo does not collect or display your CI runs —
the drift check is a command that exits 0 (pass) or 1 (drift), and GitHub
reports that like any other check:
- On a pull request, it appears as a status check — green tick or red ✗ next to the PR, with drift able to block the merge if you make the check required (Settings → Branches → branch protection).
- In the Actions tab, each run’s full log lists exactly what drifted
(
[missing_column] CUST.EMAIL, …). - GitHub emails you (per your notification settings) when a run you’re involved in fails.
So the loop is: push → GitHub runs it → you see red/green on the PR and the details in the Actions log. There’s nothing to check back inside Sqemo.
Security summary
- Read-only: only
information_schema/ the catalog is queried; the connection is opened read-only. The tool never writes to your database. - Your database URL is used by the local (or CI) process only and is never sent to Sqemo servers.
- Prefer a read-only DB account, and the
--schemadump path when you’d rather not hand credentials to CI at all.