How to Use the pgcli Tool in PostgreSQL

pgcli is a modern command-line client for the postgres that makes working with databases faster and more convenient. It provides features such as syntax highlighting, auto-completion, formatted query results, and customizable prompts, making it easier to write and manage sql commands.

In this article, we will explore how to install pgcli, connect to postgres databases, understand its commonly used options, and see practical examples of how these features can improve the command-line experience.

In Linux, we can easily install this by using the sudo apt command like this.

sudo apt install pgcli

Check the installed version.

pgcli --version

Result:

Version: 3.3.1

Use the help command and check the available options we can use with the pgcli tool.

pgcli --help

Result:

Usage: pgcli [OPTIONS] [DBNAME] [USERNAME]
Options:
  -h, --host TEXT            Host address of the postgres database.
  -p, --port INTEGER         Port number at which the postgres instance is
                             listening.
  -U, --username TEXT        Username to connect to the postgres database.
  -u, --user TEXT            Username to connect to the postgres database.
  -W, --password             Force password prompt.
  -w, --no-password          Never prompt for password.
  --single-connection        Do not use a separate connection for completions.
  -v, --version              Version of pgcli.
  -d, --dbname TEXT          database name to connect to.
  --pgclirc FILE             Location of pgclirc file.
  -D, --dsn TEXT             Use DSN configured into the [alias_dsn] section
                             of pgclirc file.
  --list-dsn                 list of DSN configured into the [alias_dsn]
                             section of pgclirc file.
  --row-limit INTEGER        Set threshold for row limit prompt. Use 0 to
                             disable prompt.
  --less-chatty              Skip intro on startup and goodbye on exit.
  --prompt TEXT              Prompt format (Default: "\u@\h:\d> ").
  --prompt-dsn TEXT          Prompt format for connections using DSN aliases
                             (Default: "\u@\h:\d> ").
  -l, --list                 list available databases, then exit.
  --auto-vertical-output     Automatically switch to vertical output mode if
                             the result is wider than the terminal width.
  --warn [all|moderate|off]  Warn before running a destructive query.
  --help                     Show this message and exit.

Check the current clusters running in your system like this.

pg_lsclusters 

Result:

Ver Cluster Port Status Owner    Data directory               Log file
14  main    5435 online postgres /var/lib/postgresql/14/main  /var/log/postgresql/postgresql-14-main.log
18  main2   5433 online postgres /var/lib/postgresql/18/main2 /var/log/postgresql/postgresql-18-main2.log
19  main    5436 online postgres /var/lib/postgresql/19/main  /var/log/postgresql/postgresql-19-main.log

We can also use the pg_lscluster command in three ways.

pg_lsclusters --help

Result:

Usage: /usr/bin/pg_lsclusters [-hjs]
Options:
  -h --no-header   Omit column headers in output
  -j --json        JSON output
  -s --start-conf  Include start.conf information in status column
     --help        Print help

Now, use the pg_lsclusters command with the -h, and we can see the output should hide the header columns.

pg_lsclusters -h

Result:

14 main  5435 online postgres /var/lib/postgresql/14/main  /var/log/postgresql/postgresql-14-main.log
18 main2 5433 online postgres /var/lib/postgresql/18/main2 /var/log/postgresql/postgresql-18-main2.log
19 main  5436 online postgres /var/lib/postgresql/19/main  /var/log/postgresql/postgresql-19-main.log

Use the -j flag with the pg_lsclusters command to see the output in JSON array format, and this output contains more details about each cluster.

pg_lsclusters -j

Result:

[{"version":"14","logfile":"/var/log/postgresql/postgresql-14-main.log","port":"5435","ownergid":137,"running":1,"pgdata":"/var/lib/postgresql/14/main","owneruid":129,"configuid":129,"configdir":"/etc/postgresql/14/main","cluster":"main","start":"auto","configfile":"/etc/postgresql/14/main/postgresql.conf","socketdir":"/var/run/postgresql","config":{"max_wal_size":"1GB","ssl_key_file":"/etc/ssl/private/ssl-cert-snakeoil.key","datestyle":"iso, dmy","ident_file":"/etc/postgresql/14/main/pg_ident.conf","lc_time":"en_IN","shared_buffers":"128MB","data_directory":"/var/lib/postgresql/14/main","lc_monetary":"en_IN","hba_file":"/etc/postgresql/14/main/pg_hba.conf","ssl_cert_file":"/etc/ssl/certs/ssl-cert-snakeoil.pem","max_connections":"100","stats_temp_directory":"/var/run/postgresql/14-main.pg_stat_tmp","log_timezone":"Asia/Kolkata","min_wal_size":"80MB","lc_numeric":"en_IN","unix_socket_directories":"/var/run/postgresql","default_text_search_config":"pg_catalog.english","log_line_prefix":"%m [%p] %q%u@%d ","port":"5435","cluster_name":"14/main","timezone":"Asia/Kolkata","dynamic_shared_memory_type":"posix","ssl":"on","external_pid_file":"/var/run/postgresql/14-main.pid","lc_messages":"en_IN"}},{"socketdir":"/var/run/postgresql","configfile":"/etc/postgresql/18/main2/postgresql.conf","config":{"lc_monetary":"en_IN","hba_file":"/etc/postgresql/18/main2/pg_hba.conf","ssl_cert_file":"/etc/ssl/certs/ssl-cert-snakeoil.pem","max_connections":"100","autovacuum_worker_slots":"16","shared_buffers":"128MB","data_directory":"/var/lib/postgresql/18/main2","default_table_access_method":"heap","ident_file":"/etc/postgresql/18/main2/pg_ident.conf","lc_time":"en_IN","max_wal_size":"1GB","ssl_key_file":"/etc/ssl/private/ssl-cert-snakeoil.key","datestyle":"iso, dmy","external_pid_file":"/var/run/postgresql/18-main2.pid","ssl":"on","lc_messages":"en_IN","timezone":"Asia/Kolkata","dynamic_shared_memory_type":"posix","cluster_name":"18/main2","min_wal_size":"80MB","log_line_prefix":"%m [%p] %q%u@%d ","port":"5433","lc_numeric":"en_IN","default_text_search_config":"pg_catalog.english","unix_socket_directories":"/var/run/postgresql","shared_preload_libraries":"","log_timezone":"Asia/Kolkata"},"version":"18","ownergid":137,"pgdata":"/var/lib/postgresql/18/main2","running":1,"owneruid":129,"logfile":"/var/log/postgresql/postgresql-18-main2.log","port":"5433","configdir":"/etc/postgresql/18/main2","cluster":"main2","start":"auto","configuid":129},{"port":"5436","logfile":"/var/log/postgresql/postgresql-19-main.log","ownergid":137,"owneruid":129,"running":1,"pgdata":"/var/lib/postgresql/19/main","configuid":129,"configdir":"/etc/postgresql/19/main","start":"auto","cluster":"main","version":"19","config":{"max_wal_size":"8192MB","ssl_key_file":"/etc/ssl/private/ssl-cert-snakeoil.key","max_parallel_workers_per_gather":"4","datestyle":"iso, mdy","ident_file":"/etc/postgresql/19/main/pg_ident.conf","checkpoint_completion_target":"0.90","effective_cache_size":"23GB","lc_time":"C.UTF-8","shared_buffers":"8GB","data_directory":"/var/lib/postgresql/19/main","autovacuum_worker_slots":"16","lc_monetary":"C.UTF-8","max_parallel_workers":"16","hba_file":"/etc/postgresql/19/main/pg_hba.conf","ssl_cert_file":"/etc/ssl/certs/ssl-cert-snakeoil.pem","max_connections":"100","shared_preload_libraries":"pg_stat_statements,hypopg","max_worker_processes":"16","default_statistics_target":"200","log_timezone":"Asia/Kolkata","effective_io_concurrency":"200","work_mem":"18MB","min_wal_size":"2048MB","lc_numeric":"C.UTF-8","unix_socket_directories":"/var/run/postgresql","max_parallel_maintenance_workers":"4","default_text_search_config":"pg_catalog.english","maintenance_work_mem":"2GB","log_line_prefix":"%m [%p] %q%u@%d ","port":"5436","random_page_cost":"1.10","cluster_name":"19/main","dynamic_shared_memory_type":"posix","timezone":"Asia/Kolkata","ssl":"on","external_pid_file":"/var/run/postgresql/19-main.pid","lc_messages":"C.UTF-8"},"configfile":"/etc/postgresql/19/main/postgresql.conf","socketdir":"/var/run/postgresql"}]

Here each json array represents the each cluster-related metadata that includes

  • Postgres version (version)
  • Cluster name (cluster)
  • Port number (port)
  • Running status (running)
  • Startup configuration (start)
  • Data directory path (pgdata)
  • Configuration directory (configdir)
  • Main configuration file path (configfile)
  • Log file path (logfile)
  • Unix socket directory (socketdir)
  • Owner user ID (owneruid)
  • Owner group ID (ownergid)
  • Configuration owner user ID (configuid)
  • Configuration parameters (config), which include settings such as max_connections, shared_buffers, shared_preload_libraries, max_wal_size, timezone, ssl, hba_file, ident_file, and many other PostgreSQL configuration options.

We can use the -s flag to include the start.conf information in the output of pg_lsclusters like this.

pg_lsclusters -s

Result:

Ver Cluster Port Status      Owner    Data directory               Log file
14  main    5435 online,auto postgres /var/lib/postgresql/14/main  /var/log/postgresql/postgresql-14-main.log
18  main2   5433 online,auto postgres /var/lib/postgresql/18/main2 /var/log/postgresql/postgresql-18-main2.log
19  main    5436 online,auto postgres /var/lib/postgresql/19/main  /var/log/postgresql/postgresql-19-main.log

Inspect the contents of the start.conf file of postgres like this.

sudo cat /etc/postgresql/19/main/start.conf

Result:

# Automatic startup configuration
#   auto: automatically start the cluster
#   manual: manual startup with pg_ctlcluster/postgresql@.service only
#   disabled: refuse to start cluster
# See pg_createcluster(1) for details. When running from systemd,
# invoke 'systemctl daemon-reload' after editing this file.
auto

Now, use the pgcli tool in postgres like this

sudo -u postgres pgcli -U postgres -d postgres -p 5436

Result:

Server: PostgreSQL 19beta2
Version: 3.3.1
Home: http://pgcli.com
postgres>

Now, when you enter any commands in psql terminal, it will recommend the syntax.

How to Use the pgcli Tool in PostgreSQL-cybrosys

Now, try any other commands.

How to Use the pgcli Tool in PostgreSQL-cybrosys

Now, explore each option one by one.

-h, --host TEXT

It represents the address of the postgres database where the pgcli connects.

-p, --port INTEGER       

It represents the port number at which the postgres instance is listening.

-U, --username TEXT

It represents the username to connect to the postgres database.

-u, --user TEXT            

This is the same as the -U flag, and it represents the username to connect to the postgres database.

-W, --password            

This option makes the force password prompt.

 -w, --no-password         

This option makes not prompt for password.

--single-connection        

This flag makes the connection where you do not use a separate connection for completions.

-v, --version

This displays the version of the pgcli tool.

-d, --dbname TEXT          

This represents the database name to connect to.

-l, --list                 list available databases, then exit.

Now try the -l flag with the pgcli command like this.

sudo -u postgres pgcli -U postgres -d postgres -p 5436 -l

Result:

List of databases
+-----------+----------+----------+---------+---------+------------------------------------+
| Name      | Owner    | Encoding | Collate | Ctype   | Access privileges                  |
+-----------+----------+----------+---------+---------+------------------------------------+
| postgres  | postgres | UTF8     | C.UTF-8 | C.UTF-8 | <null>                             |
| template0 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres\npostgres=CTc/postgres |
| template1 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres\npostgres=CTc/postgres |
+-----------+----------+----------+---------+---------+------------------------------------+
SELECT 3

Now, these are the two flags that are related to the dsn alias.

-D, --dsn TEXT             Use DSN configured into the [alias_dsn] section
                             of pgclirc file.
  --list-dsn                 list of DSN configured into the [alias_dsn]
                             section of pgclirc file.

These two options are related to each other.

In this pgcli tool, there is a config file, and we can see its configuration like this.

cat ~/.config/pgcli/config

Result:

How to Use the pgcli Tool in PostgreSQL-cybrosys

We can add the new dsn alias like this in the config file of pgcli.

[alias_dsn]
# example_dsn = postgresql://[user[:password]@][netloc][:port][/dbname]
pg18 = host=localhost port=5433 dbname=postgres user=postgres

Now, use the - - list-dsn flag like this.

pgcli --list-dsn

Result:

pg18 : host=localhost port=5433 dbname=postgres user=postgres

Now, we can connect to the psql by using this dns alias like this.

 sudo -u postgres pgcli -D pg18

Result:

Server: PostgreSQL 19beta2
Version: 3.3.1
Home: http://pgcli.com
postgres>

This will show the dns alias we set earlier in the conf file of pgcli.

  --row-limit INTEGER        Set threshold for row limit prompt. Use 0 to
                             disable prompt.

Now, use this in the pgcli command like this.

sudo -u postgres pgcli -U postgres -d postgres -p 5436  --row-limit 10

Result:

Server: PostgreSQL 19beta2
Version: 3.3.1
Home: http://pgcli.com
postgres> select count(*) from employee;
+-------+
| count |
|-------|
| 10000 |
+-------+
SELECT 1
Time: 0.008s
postgres> select * from employee;
The result was limited to 10 rows
+----+-------------+------------+----------+--------------+
| id | name        | department | salary   | joining_date |
|----+-------------+------------+----------+--------------|
| 1  | Employee_1  | Sales      | 64607.81 | 2026-09-18   |
| 2  | Employee_2  | IT         | 88298.65 | 2026-09-17   |
| 3  | Employee_3  | Finance    | 75115.65 | 2026-09-16   |
| 4  | Employee_4  | Marketing  | 94059.67 | 2026-09-15   |
| 5  | Employee_5  | HR         | 63685.11 | 2026-09-14   |
| 6  | Employee_6  | Sales      | 38706.06 | 2026-09-13   |
| 7  | Employee_7  | IT         | 82639.43 | 2026-09-12   |
| 8  | Employee_8  | Finance    | 55357.04 | 2026-09-11   |
| 9  | Employee_9  | Marketing  | 86336.69 | 2026-09-10   |
| 10 | Employee_10 | HR         | 45088.87 | 2026-09-09   |
+----+-------------+------------+----------+--------------+
SELECT 10
Time: 0.008s
postgres>

The total number of records in the employee table is 10000. But after we use the --row-limit flag to 100, we can only get the 100 records total when we execute the select * query from the employee table.

  --less-chatty              Skip intro on startup and goodbye on exit.

Use the --less-chatty flag in pgcli like this.

sudo -u postgres pgcli -U postgres -d postgres -p 5436  --less-chatty

Result:

postgres> exit

This didn't show the server version message, and there was no goodbye at the time when we exited from the postgres.

  --prompt TEXT              Prompt format (Default: "\u@\h:\d> ").

Use the –prompt flag with pgcli command, and it looks like this.

sudo -u postgres pgcli -U postgres -d postgres -p 5436  --prompt PG19

Result:

Server: PostgreSQL 19beta2
Version: 3.3.1
Home: http://pgcli.com
PG19exit
Goodbye!

Now, use the –prompt flag with pgcli on another port.

sudo -u postgres pgcli -U postgres -d postgres -p 5435  --prompt PG14

Result:

Server: PostgreSQL 14.24 (Ubuntu 14.24-0ubuntu0.22.04.1)
Version: 3.3.1
Home: http://pgcli.com
PG14

The --prompt option does not affect the connection. It only changes what we see before typing commands, making it easier to identify the current session.

  --prompt-dsn TEXT          Prompt format for connections using DSN aliases
                             (Default: "\u@\h:\d> ").

Now, use this with the pgcli command like this.

sudo -u postgres pgcli -D  pg18 --prompt-dsn PG18

Result:

Server: PostgreSQL 18
Version: 3.3.1
Home: http://pgcli.com
PG18

There is only one difference between these two flags named –prompt text and –prompt-dsn text.

This flag is mainly used to connect through the dsn alias.

  --auto-vertical-output     Automatically switch to vertical output mode if
                             the result is wider than the terminal width.

Usage of --auto-vertical-output with the pgcli command like this.

sudo -u postgres pgcli -U postgres -d postgres -p 5436 --auto-vertical-output

Result:

Server: PostgreSQL 19beta2
Version: 3.3.1
Home: http://pgcli.com
postgres> select * from pg_stat_database;
-[ RECORD 1 ]-------------------------
datid                      | 0
datname                    | <null>
numbackends                | 0
xact_commit                | 0
xact_rollback              | 0
blks_read                  | 589
blks_hit                   | 234253
tup_returned               | 87204
tup_fetched                | 42726
tup_inserted               | 29
tup_updated                | 4
tup_deleted                | 0
conflicts                  | 0
temp_files                 | 0
temp_bytes                 | 0
deadlocks                  | 0
checksum_failures          | 0
checksum_last_failure      | <null>
blk_read_time              | 0.0
blk_write_time             | 0.0
session_time               | 0.0
active_time                | 0.0
idle_in_transaction_time   | 0.0
sessions                   | 0
sessions_abandoned         | 0
sessions_fatal             | 0
sessions_killed            | 0
parallel_workers_to_launch | 0
parallel_workers_launched  | 0
stats_reset                | <null>

Now, the result should be displayed in the vertical mode.

  --warn [all|moderate|off]  Warn before running a destructive query.

Usage of the –warn flag with pgcli looks like this.

sudo -u postgres pgcli -U postgres -d postgres -p 5436 --warn all

Result:

Server: PostgreSQL 19beta2
Version: 3.3.1
Home: http://pgcli.com
postgres> drop table demo;
You're about to run a destructive command.
Do you want to proceed? (y/n): y
Your call!
DROP TABLE
Time: 0.029s

pgcli offers a more user-friendly way to work with postgresql from the terminal. By learning its installation process, connection methods, configuration options, and useful command-line flags, we can perform database tasks more efficiently and make everyday postgresql administration easier.

Exploring these features in your own environment will help you become more comfortable and productive when managing the postgresql databases.

WhatsApp