Skip to content

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:

bash
cd /opt/songbird/server

TIP

You can also run every database command interactively via the Deployment Script (songbird-deploy).

Conventions ​

A few rules apply across all commands:

ConventionDetail
-- separatorWhen running through npm, place -- before any flags or arguments so npm forwards them to the script (e.g. npm run db:backup -- --password "secret").
SelectorsCommands that target a user, chat, or file accept either a numeric id or a name (username / group username / stored file name).
Force flagsDestructive commands prompt for confirmation. Pass -y or --yes to skip the prompt in non-interactive contexts.
--allBulk delete commands refuse to run without an explicit --all when no selector is given.
Built-in helpRun 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= and Group= of songbird.service, including systemd overrides. A missing Group= uses the service user's primary group. When root invokes a command for a non-root service account, the launcher repairs only this installation's data/ 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 ​

CommandPurpose
npm run db:helpPrint the built-in command guide.
npm run db:backupCreate an engine-native database backup.
npm run db:restoreRestore an engine-native database backup.
npm run db:vacuumCompact SQLite or run PostgreSQL VACUUM ANALYZE.
npm run db:migrateApply pending database migrations.
npm run db:resetWipe database content and uploaded message files.
npm run db:deleteDelete the database file.
npm run db:inspectPrint a full summary (users, chats, messages, files, disk).
npm run db:chat:inspectInspect chats only.
npm run db:user:inspectInspect users only.
npm run db:file:inspectInspect files only.
npm run db:user:createCreate a single user.
npm run db:user:generateGenerate random test users.
npm run db:user:editEdit a user profile.
npm run db:user:banToggle a user's ban state.
npm run db:user:verifyToggle a user's verified status.
npm run db:user:deleteDelete one, many, or all users.
npm run db:chat:createCreate a group or channel (optionally a Remote Channel).
npm run db:chat:addAdd members to a group or channel.
npm run db:chat:editEdit a chat profile, ownership, or Remote Channel config.
npm run db:chat:verifyToggle a chat's verified status.
npm run db:chat:deleteDelete one, many, or all chats.
npm run db:file:deleteDelete uploaded message files and/or avatars.
npm run db:message:generateGenerate random messages between two users.
npm run remote:configureConfigure Telegram credentials for Remote Channel.
npm run storage:migrateMigrate 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.db to songbird-backup-<timestamp>.db.
  • PostgreSQL: creates songbird-backup-<timestamp>.dump with pg_dump --format=custom.
bash
# SQLite or PostgreSQL; the extension is selected from DB_CLIENT
npm run db:backup

INFO

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 / FlagRequiredDescription
--file <path>NoPath to a .db backup in SQLite mode or a .dump archive in PostgreSQL mode.
-y, --yesNoSkip the confirmation prompt.
bash
npm run db:restore -- -y --file /path/to/songbird-backup.db
npm run db:restore -- -y --file /path/to/songbird-backup.dump

PostgreSQL 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).

FlagRequiredDescription
-y, --yesNoSkip the confirmation prompt.
bash
npm run db:vacuum -- -y

Migrating 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:

bash
# Apply migrations to create schema tables in PostgreSQL
npm run db:migrate

2. Install pgloader ​

bash
# Debian / Ubuntu
sudo apt-get install -y pgloader

3. Run migration with pgloader ​

bash
pgloader ./data/songbird.db postgresql://songbird:password@localhost:5432/songbird

Or using a songbird.load configuration file for fine-grained control:

lisp
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';
bash
pgloader songbird.load

db:migrate ​

Applies any pending migrations. Migrations also run automatically on server start.

bash
npm run db:migrate

db:reset ​

Wipes database content and local uploaded message files.

FlagRequiredDescription
-y, --yesNoSkip the confirmation prompt.
--recreateNoRecreate a fresh database after wiping (implied with -y).
--no-recreateNoWipe without recreating the database.
bash
npm run db:reset -- -y --recreate
npm run db:reset -- -y --no-recreate

Online 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.

FlagRequiredDescription
-y, --yesNoSkip the confirmation prompt.
bash
npm run db:delete -- -y

PostgreSQL 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 / FlagRequiredDefaultDescription
--limit <n>No25Max rows listed per entity (1-1000). Also accepted as a positional number.
bash
npm run db:inspect
npm run db:inspect -- --limit 50
npm run db:chat:inspect
npm run db:user:inspect
npm run db:file:inspect

Users ​

db:user:create ​

Creates a single user. Accepts named flags or three positional arguments (nickname, username, password).

FlagPositionalRequiredDescription
--nickname <value>1stYesDisplay name. Max length follows NICKNAME_MAX_CHARS.
--username <value>2ndYesLowercase letters, numbers, ., _. Min 3 chars, max follows USERNAME_MAX_CHARS.
--password <value>3rdYesAccount password (bcrypt-hashed on save).
--role <owner|admin|user>4thNoUser role.
bash
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.

FlagPositionalRequiredDefaultDescription
--count <n>1stNo10Number of users to create (1-5000).
--password <value>2ndNoPassw0rd!Shared password for all generated users.
--nickname-prefix <value>—NoUserPrefix for generated nicknames.
--username-prefix <value>—NouserPrefix for generated usernames.
bash
npm run db:user:generate -- --count 50 --password "12345678"
npm run db:user:generate -- --count 50 --password "12345678" --nickname-prefix Member --username-prefix member

db:user:edit ​

Edits a user profile. The first positional argument is the user selector (id or username).

Argument / FlagRequiredDescription
<user-id-or-username>YesThe user to edit.
--username <value>NoNew username (same rules as create).
--nickname <value>NoNew display name.
--avatar-url <value>NoAvatar URL, e.g. /api/uploads/avatars/file.png.
--status <online|invisible>NoPresence status.
--color <#hex>NoProfile color, e.g. #10b981.
--role <owner|admin|user>NoUser role.
bash
npm run db:user:edit -- songbird.sage --nickname "Songbird Sage" --color "#ff6b6b"
npm run db:user:edit -- 1 --username songbird.admin --status invisible

db:user:ban ​

Toggles a user's ban state. Running it again unbans. Banning also expires all of the user's sessions.

Argument / FlagRequiredDescription
<user-id-or-username>YesThe user to ban or unban.
-y, --yesNoSkip the confirmation prompt.
bash
npm run db:user:ban -- songbird.sage
# run again to unban:
npm run db:user:ban -- songbird.sage

db:user:verify ​

Toggles a user's verified status. Run the command again for the same user to remove verification.

ArgumentRequiredDescription
<user-id-or-username>YesThe user to verify or unverify.
bash
npm run db:user:verify -- songbird.sage
# run again to unverify:
npm run db:user:verify -- songbird.sage

db: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 / FlagRequiredDescription
<user-id-or-username> [more...]ConditionalOne or more users to delete. Required unless --all is given.
--allConditionalDelete every user. Required when no selector is provided.
-y, --yesNoSkip the confirmation prompt.
bash
npm run db:user:delete -- songbird.sage -y
npm run db:user:delete -- --all -y

Chats ​

db:chat:create ​

Creates a group or channel. Channels can optionally be configured as a Remote Channel at creation time.

FlagRequiredDescription
--type <group|channel>YesChat type.
--name <value>YesDisplay name.
--owner <user>YesOwner user (id or username).
--username <value>YesPublic handle for the chat.
--visibility <public|private>NoVisibility (defaults to public).
--users <a,b,c>NoComma-separated initial members.
--remote-channel <source>NoTelegram source (@name, t.me link, or numeric id). Channels only; requires REMOTE_CHANNEL=true.
--sync-metadataNoCopy the source's title/avatar into the channel.
--stream-mediaNoDownload source media into Songbird uploads.
bash
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-media

db: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 / FlagRequiredDescription
<chat-id-or-username>YesThe target chat.
<user> [more...]ConditionalOne or more users to add. Required unless --all is given.
--allConditionalAdd every user in the database.
--forceNoRe-add users who previously left the chat.
bash
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 --force

db:chat:edit ​

Edits a chat profile, transfers ownership, or manages its Remote Channel. The first positional argument is the chat selector.

Profile flags:

FlagDescription
--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-invitesToggle member invites (private chats only; public chats always allow them).

Remote Channel config flags (channels only):

FlagDescription
--remote-channel <source>Set/replace the Telegram source.
--sync-metadata / --no-sync-metadataEnable/disable metadata sync.
--stream-media / --no-stream-mediaEnable/disable media streaming.

Remote Channel control flags:

FlagDescription
--enable-remote / --disable-remoteEnable or disable the configured source.
--pause-queue / --resume-queuePause or resume mirror queue processing.
--skip-queueSkip the current queue item.
--skip-all-queueSkip all pending/retry queue items.
bash
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-queue

db:chat:verify ​

Toggles a group or channel's verified status. Run the command again for the same chat to remove verification.

ArgumentRequiredDescription
<chat-id-or-username>YesThe group or channel to verify or unverify.
bash
npm run db:chat:verify -- core.team
# run again to unverify:
npm run db:chat:verify -- core.team

db:chat:delete ​

Deletes one, many, or all chats and their related data (messages, members, files).

Argument / FlagRequiredDescription
<chat-id-or-username> [more...]ConditionalOne or more chats to delete. Required unless --all is given.
--allConditionalDelete every chat. Required when no selector is provided.
-y, --yesNoSkip the confirmation prompt.
bash
npm run db:chat:delete -- 12 -y
npm run db:chat:delete -- core.team -y
npm run db:chat:delete -- --all -y

Files ​

db:file:delete ​

Deletes uploaded message files and/or avatar files, both from the database and from disk.

Argument / FlagRequiredDescription
<file-id-or-name> [more...]ConditionalFile ids or stored file names to delete. Required unless --all is given.
--allConditionalDelete all uploaded files (message files + avatars).
-y, --yesNoSkip the confirmation prompt.
bash
npm run db:file:delete -- 42 -y
npm run db:file:delete -- stored-file-name.ext -y
npm run db:file:delete -- --all -y

Messages ​

db:message:generate ​

Generates random messages in one chat between two users. Accepts positional arguments or named flags.

Argument / FlagPositionalRequiredDefaultDescription
--chatId <id>1stYes—Target chat id.
--userA <user>2ndYes—First participant (id or username).
--userB <user>3rdYes—Second participant (id or username).
--count <n>4thNo1Number of messages (1-10000).
--days <n>5thNo7Spread messages across the last N days (1-365).
bash
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 7

Remote 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.

bash
npm run remote:configure

See 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.

FlagShorthandDescription
--dry-runPreview legacy objects.
--yes-ySkip interactive confirmation prompt.
--help-hDisplay command help.
bash
npm run storage:migrate

Concurrency 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:

bash
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

Released under the MIT License.