Database Commands
Songbird supports both SQLite (default) and PostgreSQL database engines, and ships a set of npm scripts for managing the database, users, chats, files, and backups from the command line. Run them from the server/ directory:
cd /opt/songbird/serverTIP
You can also run every database command interactively via the Deployment Script (songbird-deploy).
Conventions
A few rules apply across all commands:
| Convention | Detail |
|---|---|
-- separator | When running through npm, place -- before any flags or arguments so npm forwards them to the script (e.g. npm run db:backup -- --password "secret"). |
| Selectors | Commands that target a user, chat, or file accept either a numeric id or a name (username / group username / stored file name). |
| Force flags | Destructive commands prompt for confirmation. Pass -y or --yes to skip the prompt in non-interactive contexts. |
--all | Bulk delete commands refuse to run without an explicit --all when no selector is given. |
| Built-in help | Run npm run db:help for a condensed cheat sheet of every command. |
Data directory ownership
Supported database commands use a pre-Node launcher and follow Songbird's runtime account:
- Docker: The command runs as the container's current UID/GID. Docker does not use
songbird.service. - systemd: The command follows the effective
User=andGroup=ofsongbird.service, including systemd overrides. A missingGroup=uses the service user's primary group. When root invokes a command for a non-root service account, the launcher repairs only this installation'sdata/directory and then switches to that configured account. - Manual/no-systemd: The command uses the caller's current account. It does not create an account or attempt ownership repair.
If User= is missing or User=root, the systemd command remains root: it does not run chown or change users. An explicit Group= is still preserved, so User=root and Group=appgroup executes as root:appgroup. For safety, the root/non-root-systemd repair path accepts only the deployed instance's own data/ directory next to the launcher (/opt/songbird/data in the standard installation); it rejects an overridden DATA_DIR rather than recursively changing an arbitrary path.
DATA_DIR contains Songbird-managed SQLite data, uploads, and backups. PostgreSQL server data is managed externally by PostgreSQL and is not stored in, or changed by, this directory.
WARNING
Do not run individual scripts with sudo node or sudo npm. Those direct invocations bypass the launcher and are unsupported. Use the documented npm run db:* commands instead.
Quick reference
| Command | Purpose |
|---|---|
npm run db:help | Print the built-in command guide. |
npm run db:backup | Create an engine-native database backup. |
npm run db:restore | Restore an engine-native database backup. |
npm run db:vacuum | Compact SQLite or run PostgreSQL VACUUM ANALYZE. |
npm run db:migrate | Apply pending database migrations. |
npm run db:reset | Wipe database content and uploaded message files. |
npm run db:delete | Delete the database file. |
npm run db:inspect | Print a full summary (users, chats, messages, files, disk). |
npm run db:chat:inspect | Inspect chats only. |
npm run db:user:inspect | Inspect users only. |
npm run db:file:inspect | Inspect files only. |
npm run db:user:create | Create a single user. |
npm run db:user:generate | Generate random test users. |
npm run db:user:edit | Edit a user profile. |
npm run db:user:ban | Toggle a user's ban state. |
npm run db:user:verify | Toggle a user's verified status. |
npm run db:user:delete | Delete one, many, or all users. |
npm run db:chat:create | Create a group or channel (optionally a Remote Channel). |
npm run db:chat:add | Add members to a group or channel. |
npm run db:chat:edit | Edit a chat profile, ownership, or Remote Channel config. |
npm run db:chat:verify | Toggle a chat's verified status. |
npm run db:chat:delete | Delete one, many, or all chats. |
npm run db:file:delete | Delete uploaded message files and/or avatars. |
npm run db:message:generate | Generate random messages between two users. |
npm run remote:configure | Configure Telegram credentials for Remote Channel. |
npm run storage:migrate | Migrate object storage keys to unified layout and rewrite DB records. |
Backup & restore
db:backup
Creates a timestamped, engine-native backup in data/backups/:
- SQLite: copies
songbird.dbtosongbird-backup-<timestamp>.db. - PostgreSQL: creates
songbird-backup-<timestamp>.dumpwithpg_dump --format=custom.
# SQLite or PostgreSQL; the extension is selected from DB_CLIENT
npm run db:backupINFO
Backups contain database content only. They do not include .env, local uploads, or objects in remote storage; manage those separately.
The PostgreSQL client tools pg_dump, pg_restore, vacuumdb, dropdb, and createdb must be available in PATH, and the configured database user needs the corresponding PostgreSQL permissions.
db:restore
Restores the newest matching backup or an explicitly selected file. SQLite accepts .db files; PostgreSQL accepts native .dump archives and validates them with pg_restore --list before restoring.
| Argument / Flag | Required | Description |
|---|---|---|
--file <path> | No | Path to a .db backup in SQLite mode or a .dump archive in PostgreSQL mode. |
-y, --yes | No | Skip the confirmation prompt. |
npm run db:restore -- -y --file /path/to/songbird-backup.db
npm run db:restore -- -y --file /path/to/songbird-backup.dumpPostgreSQL must be offline
Stop Songbird before running PostgreSQL db:restore. Native pg_restore --clean replaces database objects and cannot safely run through the live Songbird process. Start or restart Songbird only after the command succeeds.
Maintenance
db:vacuum
Compacts SQLite with VACUUM; in PostgreSQL mode it runs native vacuumdb --analyze (VACUUM ANALYZE).
| Flag | Required | Description |
|---|---|---|
-y, --yes | No | Skip the confirmation prompt. |
npm run db:vacuum -- -yMigrating from SQLite to PostgreSQL
For converting a SQLite database to PostgreSQL, standard industry tools such as pgloader provide robust, battle-tested migration with automatic type mapping, sequence creation, and transaction safety.
1. Prepare target PostgreSQL database
Configure your .env with PostgreSQL connection details (DB_CLIENT=postgres and POSTGRES_* variables) and run migrations to create the schema:
# Apply migrations to create schema tables in PostgreSQL
npm run db:migrate2. Install pgloader
# Debian / Ubuntu
sudo apt-get install -y pgloader3. Run migration with pgloader
pgloader ./data/songbird.db postgresql://songbird:password@localhost:5432/songbirdOr using a songbird.load configuration file for fine-grained control:
LOAD DATABASE
FROM sqlite://./data/songbird.db
INTO postgresql://songbird:password@localhost:5432/songbird
WITH include drop, create tables, create indexes, reset sequences
SET work_mem to '16MB', maintenance_work_mem to '512MB';pgloader songbird.loaddb:migrate
Applies any pending migrations. Migrations also run automatically on server start.
npm run db:migratedb:reset
Wipes database content and local uploaded message files.
| Flag | Required | Description |
|---|---|---|
-y, --yes | No | Skip the confirmation prompt. |
--recreate | No | Recreate a fresh database after wiping (implied with -y). |
--no-recreate | No | Wipe without recreating the database. |
npm run db:reset -- -y --recreate
npm run db:reset -- -y --no-recreateOnline vs. Offline behavior
When Songbird is running, the command delegates to the authenticated local server and performs an schema-preserving reset. When Songbird is stopped, SQLite removes its database file and PostgreSQL drops the database; either engine can then be recreated and migrated.
db:delete
Deletes the SQLite database file or, in PostgreSQL mode, drops the PostgreSQL database with native dropdb.
| Flag | Required | Description |
|---|---|---|
-y, --yes | No | Skip the confirmation prompt. |
npm run db:delete -- -yPostgreSQL must be offline
Stop Songbird before PostgreSQL db:delete; dropdb --force terminates active PostgreSQL connections. Local message uploads are also removed, but remote object storage must be cleaned separately if configured.
Inspection
db:inspect and friends
Prints counts, disk usage, and per-entity rows. The db:chat:inspect, db:user:inspect, and db:file:inspect variants scope the output to one entity.
| Argument / Flag | Required | Default | Description |
|---|---|---|---|
--limit <n> | No | 25 | Max rows listed per entity (1-1000). Also accepted as a positional number. |
npm run db:inspect
npm run db:inspect -- --limit 50
npm run db:chat:inspect
npm run db:user:inspect
npm run db:file:inspectUsers
db:user:create
Creates a single user. Accepts named flags or three positional arguments (nickname, username, password).
| Flag | Positional | Required | Description |
|---|---|---|---|
--nickname <value> | 1st | Yes | Display name. Max length follows NICKNAME_MAX_CHARS. |
--username <value> | 2nd | Yes | Lowercase letters, numbers, ., _. Min 3 chars, max follows USERNAME_MAX_CHARS. |
--password <value> | 3rd | Yes | Account password (bcrypt-hashed on save). |
--role <owner|admin|user> | 4th | No | User role. |
npm run db:user:create -- --nickname "Songbird Sage" --username songbird.sage --password "12345678"
# positional form:
npm run db:user:create -- "Songbird Sage" songbird.sage "12345678"db:user:generate
Creates random test users.
| Flag | Positional | Required | Default | Description |
|---|---|---|---|---|
--count <n> | 1st | No | 10 | Number of users to create (1-5000). |
--password <value> | 2nd | No | Passw0rd! | Shared password for all generated users. |
--nickname-prefix <value> | — | No | User | Prefix for generated nicknames. |
--username-prefix <value> | — | No | user | Prefix for generated usernames. |
npm run db:user:generate -- --count 50 --password "12345678"
npm run db:user:generate -- --count 50 --password "12345678" --nickname-prefix Member --username-prefix memberdb:user:edit
Edits a user profile. The first positional argument is the user selector (id or username).
| Argument / Flag | Required | Description |
|---|---|---|
<user-id-or-username> | Yes | The user to edit. |
--username <value> | No | New username (same rules as create). |
--nickname <value> | No | New display name. |
--avatar-url <value> | No | Avatar URL, e.g. /api/uploads/avatars/file.png. |
--status <online|invisible> | No | Presence status. |
--color <#hex> | No | Profile color, e.g. #10b981. |
--role <owner|admin|user> | No | User role. |
npm run db:user:edit -- songbird.sage --nickname "Songbird Sage" --color "#ff6b6b"
npm run db:user:edit -- 1 --username songbird.admin --status invisibledb:user:ban
Toggles a user's ban state. Running it again unbans. Banning also expires all of the user's sessions.
| Argument / Flag | Required | Description |
|---|---|---|
<user-id-or-username> | Yes | The user to ban or unban. |
-y, --yes | No | Skip the confirmation prompt. |
npm run db:user:ban -- songbird.sage
# run again to unban:
npm run db:user:ban -- songbird.sagedb:user:verify
Toggles a user's verified status. Run the command again for the same user to remove verification.
| Argument | Required | Description |
|---|---|---|
<user-id-or-username> | Yes | The user to verify or unverify. |
npm run db:user:verify -- songbird.sage
# run again to unverify:
npm run db:user:verify -- songbird.sagedb:user:delete
Deletes one, many, or all users along with their sessions and messages. Owned chats are either deleted (if no members remain) or transferred to a random remaining member.
| Argument / Flag | Required | Description |
|---|---|---|
<user-id-or-username> [more...] | Conditional | One or more users to delete. Required unless --all is given. |
--all | Conditional | Delete every user. Required when no selector is provided. |
-y, --yes | No | Skip the confirmation prompt. |
npm run db:user:delete -- songbird.sage -y
npm run db:user:delete -- --all -yChats
db:chat:create
Creates a group or channel. Channels can optionally be configured as a Remote Channel at creation time.
| Flag | Required | Description |
|---|---|---|
--type <group|channel> | Yes | Chat type. |
--name <value> | Yes | Display name. |
--owner <user> | Yes | Owner user (id or username). |
--username <value> | Yes | Public handle for the chat. |
--visibility <public|private> | No | Visibility (defaults to public). |
--users <a,b,c> | No | Comma-separated initial members. |
--remote-channel <source> | No | Telegram source (@name, t.me link, or numeric id). Channels only; requires REMOTE_CHANNEL=true. |
--sync-metadata | No | Copy the source's title/avatar into the channel. |
--stream-media | No | Download source media into Songbird uploads. |
npm run db:chat:create -- --type group --name "Core Team" --owner songbird.sage --username core.team --visibility private --users songbird.sage2,songbird.sage3
npm run db:chat:create -- --type channel --name "Announcements" --owner songbird.sage --username announcements
# Channel with a Remote Channel source:
npm run db:chat:create -- --type channel --name "My Channel" --owner alice --username my_channel --remote-channel @telegram_source --sync-metadata --stream-mediadb:chat:add
Adds members to a group or channel. The first positional argument is the chat selector. Users who previously left are skipped unless --force is given.
| Argument / Flag | Required | Description |
|---|---|---|
<chat-id-or-username> | Yes | The target chat. |
<user> [more...] | Conditional | One or more users to add. Required unless --all is given. |
--all | Conditional | Add every user in the database. |
--force | No | Re-add users who previously left the chat. |
npm run db:chat:add -- core.team songbird.sage2 songbird.sage3
npm run db:chat:add -- 1 --all
npm run db:chat:add -- 1 --all --forcedb:chat:edit
Edits a chat profile, transfers ownership, or manages its Remote Channel. The first positional argument is the chat selector.
Profile flags:
| Flag | Description |
|---|---|
--name <value> | New display name. |
--username <value> | New public handle. |
--visibility <public|private> | New visibility. |
--color <#hex> | New chat color. |
--owner <user> | Transfer ownership to another user. |
--allow-member-invites / --disallow-member-invites | Toggle member invites (private chats only; public chats always allow them). |
Remote Channel config flags (channels only):
| Flag | Description |
|---|---|
--remote-channel <source> | Set/replace the Telegram source. |
--sync-metadata / --no-sync-metadata | Enable/disable metadata sync. |
--stream-media / --no-stream-media | Enable/disable media streaming. |
Remote Channel control flags:
| Flag | Description |
|---|---|
--enable-remote / --disable-remote | Enable or disable the configured source. |
--pause-queue / --resume-queue | Pause or resume mirror queue processing. |
--skip-queue | Skip the current queue item. |
--skip-all-queue | Skip all pending/retry queue items. |
npm run db:chat:edit -- core.team --name "Core Team HQ" --visibility public --color "#14b8a6"
npm run db:chat:edit -- 1 --owner songbird.sage2
# Remote Channel:
npm run db:chat:edit -- my_channel --remote-channel @new_telegram_source
npm run db:chat:edit -- my_channel --no-stream-media
npm run db:chat:edit -- my_channel --enable-remote
npm run db:chat:edit -- my_channel --pause-queue
npm run db:chat:edit -- my_channel --skip-all-queuedb:chat:verify
Toggles a group or channel's verified status. Run the command again for the same chat to remove verification.
| Argument | Required | Description |
|---|---|---|
<chat-id-or-username> | Yes | The group or channel to verify or unverify. |
npm run db:chat:verify -- core.team
# run again to unverify:
npm run db:chat:verify -- core.teamdb:chat:delete
Deletes one, many, or all chats and their related data (messages, members, files).
| Argument / Flag | Required | Description |
|---|---|---|
<chat-id-or-username> [more...] | Conditional | One or more chats to delete. Required unless --all is given. |
--all | Conditional | Delete every chat. Required when no selector is provided. |
-y, --yes | No | Skip the confirmation prompt. |
npm run db:chat:delete -- 12 -y
npm run db:chat:delete -- core.team -y
npm run db:chat:delete -- --all -yFiles
db:file:delete
Deletes uploaded message files and/or avatar files, both from the database and from disk.
| Argument / Flag | Required | Description |
|---|---|---|
<file-id-or-name> [more...] | Conditional | File ids or stored file names to delete. Required unless --all is given. |
--all | Conditional | Delete all uploaded files (message files + avatars). |
-y, --yes | No | Skip the confirmation prompt. |
npm run db:file:delete -- 42 -y
npm run db:file:delete -- stored-file-name.ext -y
npm run db:file:delete -- --all -yMessages
db:message:generate
Generates random messages in one chat between two users. Accepts positional arguments or named flags.
| Argument / Flag | Positional | Required | Default | Description |
|---|---|---|---|---|
--chatId <id> | 1st | Yes | — | Target chat id. |
--userA <user> | 2nd | Yes | — | First participant (id or username). |
--userB <user> | 3rd | Yes | — | Second participant (id or username). |
--count <n> | 4th | No | 1 | Number of messages (1-10000). |
--days <n> | 5th | No | 7 | Spread messages across the last N days (1-365). |
npm run db:message:generate -- 1 songbird.sage songbird.sage2 300 7
npm run db:message:generate -- --chatId 1 --userA songbird.sage --userB songbird.sage2 --count 300 --days 7Remote Channel configuration
remote:configure
Interactively configures Telegram credentials for the Remote Channel feature. This sets up REMOTE_CHANNEL_TELEGRAM_API_ID, REMOTE_CHANNEL_TELEGRAM_API_HASH, and REMOTE_CHANNEL_TELEGRAM_SESSION_STRING in your .env file.
npm run remote:configureSee Remote Channel Setup for the complete guide, including how to obtain API credentials.
Object Storage
storage:migrate
Migrates object-storage keys from the legacy root-level layout to the unified layout and updates database columns.
| Flag | Shorthand | Description |
|---|---|---|
--dry-run | Preview legacy objects. | |
--yes | -y | Skip interactive confirmation prompt. |
--help | -h | Display command help. |
npm run storage:migrateConcurrency Guard
storage:migrate refuses to run if the Songbird server process is actively running, preventing race conditions with live uploads. Stop the server before executing.
Running commands via Docker
To run database and maintenance commands inside a Docker container:
docker compose exec songbird npm --prefix /app/server run db:backup
docker compose exec songbird npm --prefix /app/server run db:migrate
docker compose exec songbird npm --prefix /app/server run db:inspect
docker compose exec songbird npm --prefix /app/server run storage:migrate -- -y