[{"data":1,"prerenderedAt":2065},["ShallowReactive",2],{"page-en-\u002Fblog\u002Fpostgresql-psql-commands":3,"related-en-\u002Fblog\u002Fpostgresql-psql-commands":2040},{"id":4,"title":5,"body":6,"date":2027,"description":2028,"extension":2029,"meta":2030,"navigation":552,"path":2031,"seo":2032,"stem":2033,"tags":2034,"translation":2038,"__hash__":2039},"pages_en\u002Fen\u002Fblog\u002Fpostgresql-psql-commands.md","PostgreSQL and psql Basics",{"type":7,"value":8,"toc":2014},"minimark",[9,14,23,29,33,155,166,181,185,188,406,409,488,492,720,726,740,744,996,1002,1006,1307,1311,1515,1524,1528,1600,1607,1610,1790,1794,1853,1864,1868,1974,1978,2010],[10,11,13],"h2",{"id":12},"introduction","Introduction",[15,16,17,18,22],"p",{},"PostgreSQL is one of the most popular relational databases in the open-source world. ",[19,20,21],"code",{},"psql"," is its command-line client: faster than GUI tools, always available on the server, and scriptable.",[15,24,25,26,28],{},"This post collects the ",[19,27,21],{}," commands and SQL patterns used most in daily work.",[10,30,32],{"id":31},"_1-connecting","1. Connecting",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","psql -U app -d appdb                         # local\npsql -h db.example.com -p 5432 -U app -d appdb\npsql \"postgresql:\u002F\u002Fapp:secret@localhost:5432\u002Fappdb\"\nsudo -u postgres psql                        # as the superuser (Linux)\ndocker compose exec db psql -U app -d appdb  # inside a container\n","bash","",[19,41,42,67,94,109,127],{"__ignoreMap":39},[43,44,47,50,54,57,60,63],"span",{"class":45,"line":46},"line",1,[43,48,21],{"class":49},"sBMFI",[43,51,53],{"class":52},"sfazB"," -U",[43,55,56],{"class":52}," app",[43,58,59],{"class":52}," -d",[43,61,62],{"class":52}," appdb",[43,64,66],{"class":65},"sHwdD","                         # local\n",[43,68,70,72,75,78,81,85,87,89,91],{"class":45,"line":69},2,[43,71,21],{"class":49},[43,73,74],{"class":52}," -h",[43,76,77],{"class":52}," db.example.com",[43,79,80],{"class":52}," -p",[43,82,84],{"class":83},"sbssI"," 5432",[43,86,53],{"class":52},[43,88,56],{"class":52},[43,90,59],{"class":52},[43,92,93],{"class":52}," appdb\n",[43,95,97,99,103,106],{"class":45,"line":96},3,[43,98,21],{"class":49},[43,100,102],{"class":101},"sMK4o"," \"",[43,104,105],{"class":52},"postgresql:\u002F\u002Fapp:secret@localhost:5432\u002Fappdb",[43,107,108],{"class":101},"\"\n",[43,110,112,115,118,121,124],{"class":45,"line":111},4,[43,113,114],{"class":49},"sudo",[43,116,117],{"class":52}," -u",[43,119,120],{"class":52}," postgres",[43,122,123],{"class":52}," psql",[43,125,126],{"class":65},"                        # as the superuser (Linux)\n",[43,128,130,133,136,139,142,144,146,148,150,152],{"class":45,"line":129},5,[43,131,132],{"class":49},"docker",[43,134,135],{"class":52}," compose",[43,137,138],{"class":52}," exec",[43,140,141],{"class":52}," db",[43,143,123],{"class":52},[43,145,53],{"class":52},[43,147,56],{"class":52},[43,149,59],{"class":52},[43,151,62],{"class":52},[43,153,154],{"class":65},"  # inside a container\n",[15,156,157,158,161,162,165],{},"To avoid typing the password every time, use a ",[19,159,160],{},"~\u002F.pgpass"," file (permissions must be ",[19,163,164],{},"600","):",[34,167,169],{"className":36,"code":168,"language":38,"meta":39,"style":39},"# host:port:database:user:password\nlocalhost:5432:appdb:app:secret\n",[19,170,171,176],{"__ignoreMap":39},[43,172,173],{"class":45,"line":46},[43,174,175],{"class":65},"# host:port:database:user:password\n",[43,177,178],{"class":45,"line":69},[43,179,180],{"class":49},"localhost:5432:appdb:app:secret\n",[10,182,184],{"id":183},"_2-psql-meta-commands","2. psql meta-commands",[15,186,187],{},"Commands starting with a backslash aren't SQL but psql's own commands, and need no semicolon.",[189,190,191,204],"table",{},[192,193,194],"thead",{},[195,196,197,201],"tr",{},[198,199,200],"th",{},"Command",[198,202,203],{},"Description",[205,206,207,218,228,238,252,262,272,282,292,302,312,322,332,342,352,362,372,382,396],"tbody",{},[195,208,209,215],{},[210,211,212],"td",{},[19,213,214],{},"\\l",[210,216,217],{},"List databases",[195,219,220,225],{},[210,221,222],{},[19,223,224],{},"\\c appdb",[210,226,227],{},"Switch to another database",[195,229,230,235],{},[210,231,232],{},[19,233,234],{},"\\dn",[210,236,237],{},"Schemas",[195,239,240,245],{},[210,241,242],{},[19,243,244],{},"\\dt",[210,246,247,248,251],{},"Tables (",[19,249,250],{},"\\dt *.*"," for all schemas)",[195,253,254,259],{},[210,255,256],{},[19,257,258],{},"\\d users",[210,260,261],{},"A table's columns, indexes and constraints",[195,263,264,269],{},[210,265,266],{},[19,267,268],{},"\\d+ users",[210,270,271],{},"Plus size and comments",[195,273,274,279],{},[210,275,276],{},[19,277,278],{},"\\di",[210,280,281],{},"Indexes",[195,283,284,289],{},[210,285,286],{},[19,287,288],{},"\\dv",[210,290,291],{},"Views",[195,293,294,299],{},[210,295,296],{},[19,297,298],{},"\\df",[210,300,301],{},"Functions",[195,303,304,309],{},[210,305,306],{},[19,307,308],{},"\\du",[210,310,311],{},"Users\u002Froles",[195,313,314,319],{},[210,315,316],{},[19,317,318],{},"\\dp users",[210,320,321],{},"Table privileges",[195,323,324,329],{},[210,325,326],{},[19,327,328],{},"\\x",[210,330,331],{},"Toggle vertical display for wide rows",[195,333,334,339],{},[210,335,336],{},[19,337,338],{},"\\timing",[210,340,341],{},"Show query duration",[195,343,344,349],{},[210,345,346],{},[19,347,348],{},"\\e",[210,350,351],{},"Edit the last query in an editor",[195,353,354,359],{},[210,355,356],{},[19,357,358],{},"\\i file.sql",[210,360,361],{},"Run SQL from a file",[195,363,364,369],{},[210,365,366],{},[19,367,368],{},"\\o out.txt",[210,370,371],{},"Write output to a file",[195,373,374,379],{},[210,375,376],{},[19,377,378],{},"\\conninfo",[210,380,381],{},"Current connection info",[195,383,384,393],{},[210,385,386,389,390],{},[19,387,388],{},"\\?"," \u002F ",[19,391,392],{},"\\h SELECT",[210,394,395],{},"psql help \u002F SQL command help",[195,397,398,403],{},[210,399,400],{},[19,401,402],{},"\\q",[210,404,405],{},"Quit",[15,407,408],{},"To run a single command and exit:",[34,410,412],{"className":36,"code":411,"language":38,"meta":39,"style":39},"psql -U app -d appdb -c \"SELECT count(*) FROM users;\"\npsql -U app -d appdb -f migration.sql\npsql -U app -d appdb -At -c \"SELECT email FROM users\" > emails.txt   # bare output\n",[19,413,414,436,454],{"__ignoreMap":39},[43,415,416,418,420,422,424,426,429,431,434],{"class":45,"line":46},[43,417,21],{"class":49},[43,419,53],{"class":52},[43,421,56],{"class":52},[43,423,59],{"class":52},[43,425,62],{"class":52},[43,427,428],{"class":52}," -c",[43,430,102],{"class":101},[43,432,433],{"class":52},"SELECT count(*) FROM users;",[43,435,108],{"class":101},[43,437,438,440,442,444,446,448,451],{"class":45,"line":69},[43,439,21],{"class":49},[43,441,53],{"class":52},[43,443,56],{"class":52},[43,445,59],{"class":52},[43,447,62],{"class":52},[43,449,450],{"class":52}," -f",[43,452,453],{"class":52}," migration.sql\n",[43,455,456,458,460,462,464,466,469,471,473,476,479,482,485],{"class":45,"line":96},[43,457,21],{"class":49},[43,459,53],{"class":52},[43,461,56],{"class":52},[43,463,59],{"class":52},[43,465,62],{"class":52},[43,467,468],{"class":52}," -At",[43,470,428],{"class":52},[43,472,102],{"class":101},[43,474,475],{"class":52},"SELECT email FROM users",[43,477,478],{"class":101},"\"",[43,480,481],{"class":101}," >",[43,483,484],{"class":52}," emails.txt",[43,486,487],{"class":65},"   # bare output\n",[10,489,491],{"id":490},"_3-creating-databases-and-users","3. Creating databases and users",[34,493,497],{"className":494,"code":495,"language":496,"meta":39,"style":39},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","CREATE ROLE app WITH LOGIN PASSWORD 'secret';\nCREATE DATABASE appdb OWNER app;\n\n-- Read-only user\nCREATE ROLE reporter WITH LOGIN PASSWORD 'secret2';\nGRANT CONNECT ON DATABASE appdb TO reporter;\nGRANT USAGE ON SCHEMA public TO reporter;\nGRANT SELECT ON ALL TABLES IN SCHEMA public TO reporter;\nALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO reporter;\n\nALTER ROLE app WITH PASSWORD 'new-secret';\nDROP ROLE reporter;\n","sql",[19,498,499,532,548,554,559,583,606,627,651,683,688,710],{"__ignoreMap":39},[43,500,501,504,507,511,514,517,520,523,526,529],{"class":45,"line":46},[43,502,503],{"class":83},"CREATE",[43,505,506],{"class":83}," ROLE",[43,508,510],{"class":509},"sTEyZ"," app ",[43,512,513],{"class":83},"WITH",[43,515,516],{"class":83}," LOGIN",[43,518,519],{"class":83}," PASSWORD",[43,521,522],{"class":101}," '",[43,524,525],{"class":52},"secret",[43,527,528],{"class":101},"'",[43,530,531],{"class":509},";\n",[43,533,534,536,539,542,545],{"class":45,"line":69},[43,535,503],{"class":83},[43,537,538],{"class":83}," DATABASE",[43,540,62],{"class":541},"s2Zo4",[43,543,544],{"class":83}," OWNER",[43,546,547],{"class":509}," app;\n",[43,549,550],{"class":45,"line":96},[43,551,553],{"emptyLinePlaceholder":552},true,"\n",[43,555,556],{"class":45,"line":111},[43,557,558],{"class":65},"-- Read-only user\n",[43,560,561,563,565,568,570,572,574,576,579,581],{"class":45,"line":129},[43,562,503],{"class":83},[43,564,506],{"class":83},[43,566,567],{"class":509}," reporter ",[43,569,513],{"class":83},[43,571,516],{"class":83},[43,573,519],{"class":83},[43,575,522],{"class":101},[43,577,578],{"class":52},"secret2",[43,580,528],{"class":101},[43,582,531],{"class":509},[43,584,586,589,592,595,597,600,603],{"class":45,"line":585},6,[43,587,588],{"class":83},"GRANT",[43,590,591],{"class":83}," CONNECT",[43,593,594],{"class":83}," ON",[43,596,538],{"class":83},[43,598,599],{"class":509}," appdb ",[43,601,602],{"class":83},"TO",[43,604,605],{"class":509}," reporter;\n",[43,607,609,611,614,617,620,623,625],{"class":45,"line":608},7,[43,610,588],{"class":83},[43,612,613],{"class":509}," USAGE ",[43,615,616],{"class":83},"ON",[43,618,619],{"class":83}," SCHEMA",[43,621,622],{"class":509}," public ",[43,624,602],{"class":83},[43,626,605],{"class":509},[43,628,630,632,635,637,640,643,645,647,649],{"class":45,"line":629},8,[43,631,588],{"class":83},[43,633,634],{"class":83}," SELECT",[43,636,594],{"class":83},[43,638,639],{"class":509}," ALL TABLES ",[43,641,642],{"class":83},"IN",[43,644,619],{"class":83},[43,646,622],{"class":509},[43,648,602],{"class":83},[43,650,605],{"class":509},[43,652,654,657,661,664,666,668,670,672,674,676,679,681],{"class":45,"line":653},9,[43,655,656],{"class":83},"ALTER",[43,658,660],{"class":659},"spNyl"," DEFAULT",[43,662,663],{"class":509}," PRIVILEGES ",[43,665,642],{"class":83},[43,667,619],{"class":83},[43,669,622],{"class":509},[43,671,588],{"class":83},[43,673,634],{"class":83},[43,675,594],{"class":83},[43,677,678],{"class":509}," TABLES ",[43,680,602],{"class":83},[43,682,605],{"class":509},[43,684,686],{"class":45,"line":685},10,[43,687,553],{"emptyLinePlaceholder":552},[43,689,691,693,695,697,699,701,703,706,708],{"class":45,"line":690},11,[43,692,656],{"class":83},[43,694,506],{"class":83},[43,696,510],{"class":509},[43,698,513],{"class":83},[43,700,519],{"class":83},[43,702,522],{"class":101},[43,704,705],{"class":52},"new-secret",[43,707,528],{"class":101},[43,709,531],{"class":509},[43,711,713,716,718],{"class":45,"line":712},12,[43,714,715],{"class":83},"DROP",[43,717,506],{"class":83},[43,719,605],{"class":509},[15,721,722,725],{},[19,723,724],{},"ALTER DEFAULT PRIVILEGES"," grants the privilege automatically on tables created later; forget it and new tables won't be readable.",[727,728,729],"blockquote",{},[15,730,731,732,735,736,739],{},"Since PostgreSQL 15, everyone's right to create tables in the ",[19,733,734],{},"public"," schema has been removed. If the app user doesn't own the database, you may need ",[19,737,738],{},"GRANT CREATE ON SCHEMA public TO app;",".",[10,741,743],{"id":742},"_4-working-with-tables","4. Working with tables",[34,745,747],{"className":494,"code":746,"language":496,"meta":39,"style":39},"CREATE TABLE users (\n    id          BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n    email       TEXT NOT NULL UNIQUE,\n    name        TEXT NOT NULL,\n    metadata    JSONB DEFAULT '{}'::jsonb,\n    created_at  TIMESTAMPTZ NOT NULL DEFAULT now()\n);\n\nALTER TABLE users ADD COLUMN last_login TIMESTAMPTZ;\nALTER TABLE users ALTER COLUMN name TYPE VARCHAR(200);\nALTER TABLE users RENAME COLUMN name TO full_name;\nCREATE INDEX idx_users_created_at ON users (created_at);\nCREATE INDEX CONCURRENTLY idx_users_meta ON users USING gin (metadata);\nTRUNCATE users RESTART IDENTITY;\nDROP TABLE IF EXISTS users;\n",[19,748,749,762,788,804,816,834,852,857,861,880,910,927,942,965,980],{"__ignoreMap":39},[43,750,751,753,756,759],{"class":45,"line":46},[43,752,503],{"class":83},[43,754,755],{"class":83}," TABLE",[43,757,758],{"class":541}," users",[43,760,761],{"class":509}," (\n",[43,763,764,767,770,773,776,779,782,785],{"class":45,"line":69},[43,765,766],{"class":509},"    id          ",[43,768,769],{"class":659},"BIGINT",[43,771,772],{"class":83}," GENERATED",[43,774,775],{"class":83}," ALWAYS",[43,777,778],{"class":83}," AS",[43,780,781],{"class":83}," IDENTITY",[43,783,784],{"class":659}," PRIMARY KEY",[43,786,787],{"class":509},",\n",[43,789,790,793,796,799,802],{"class":45,"line":96},[43,791,792],{"class":509},"    email       ",[43,794,795],{"class":659},"TEXT",[43,797,798],{"class":83}," NOT NULL",[43,800,801],{"class":83}," UNIQUE",[43,803,787],{"class":509},[43,805,806,809,812,814],{"class":45,"line":111},[43,807,808],{"class":83},"    name",[43,810,811],{"class":659},"        TEXT",[43,813,798],{"class":83},[43,815,787],{"class":509},[43,817,818,821,824,826,829,831],{"class":45,"line":129},[43,819,820],{"class":509},"    metadata    JSONB ",[43,822,823],{"class":659},"DEFAULT",[43,825,522],{"class":101},[43,827,828],{"class":52},"{}",[43,830,528],{"class":101},[43,832,833],{"class":509},"::jsonb,\n",[43,835,836,839,842,844,846,849],{"class":45,"line":585},[43,837,838],{"class":509},"    created_at  ",[43,840,841],{"class":659},"TIMESTAMPTZ",[43,843,798],{"class":83},[43,845,660],{"class":659},[43,847,848],{"class":83}," now",[43,850,851],{"class":101},"()\n",[43,853,854],{"class":45,"line":608},[43,855,856],{"class":509},");\n",[43,858,859],{"class":45,"line":629},[43,860,553],{"emptyLinePlaceholder":552},[43,862,863,865,867,870,873,876,878],{"class":45,"line":653},[43,864,656],{"class":83},[43,866,755],{"class":83},[43,868,869],{"class":509}," users ",[43,871,872],{"class":83},"ADD",[43,874,875],{"class":509}," COLUMN last_login ",[43,877,841],{"class":659},[43,879,531],{"class":509},[43,881,882,884,886,888,890,893,896,899,902,905,908],{"class":45,"line":685},[43,883,656],{"class":83},[43,885,755],{"class":83},[43,887,869],{"class":509},[43,889,656],{"class":83},[43,891,892],{"class":509}," COLUMN ",[43,894,895],{"class":83},"name",[43,897,898],{"class":83}," TYPE",[43,900,901],{"class":659}," VARCHAR",[43,903,904],{"class":509},"(",[43,906,907],{"class":83},"200",[43,909,856],{"class":509},[43,911,912,914,916,919,921,924],{"class":45,"line":690},[43,913,656],{"class":83},[43,915,755],{"class":83},[43,917,918],{"class":509}," users RENAME COLUMN ",[43,920,895],{"class":83},[43,922,923],{"class":83}," TO",[43,925,926],{"class":509}," full_name;\n",[43,928,929,931,934,937,939],{"class":45,"line":712},[43,930,503],{"class":83},[43,932,933],{"class":83}," INDEX",[43,935,936],{"class":541}," idx_users_created_at",[43,938,594],{"class":83},[43,940,941],{"class":509}," users (created_at);\n",[43,943,945,947,949,952,955,957,959,962],{"class":45,"line":944},13,[43,946,503],{"class":83},[43,948,933],{"class":83},[43,950,951],{"class":541}," CONCURRENTLY",[43,953,954],{"class":509}," idx_users_meta ",[43,956,616],{"class":83},[43,958,869],{"class":509},[43,960,961],{"class":83},"USING",[43,963,964],{"class":509}," gin (metadata);\n",[43,966,968,971,973,976,978],{"class":45,"line":967},14,[43,969,970],{"class":83},"TRUNCATE",[43,972,869],{"class":509},[43,974,975],{"class":83},"RESTART",[43,977,781],{"class":83},[43,979,531],{"class":509},[43,981,983,985,987,990,993],{"class":45,"line":982},15,[43,984,715],{"class":83},[43,986,755],{"class":83},[43,988,989],{"class":83}," IF",[43,991,992],{"class":83}," EXISTS",[43,994,995],{"class":509}," users;\n",[15,997,998,1001],{},[19,999,1000],{},"CREATE INDEX CONCURRENTLY"," builds the index without locking the table for writes; prefer it on live systems (it can't run inside a transaction).",[10,1003,1005],{"id":1004},"_5-practical-sql-patterns","5. Practical SQL patterns",[34,1007,1009],{"className":494,"code":1008,"language":496,"meta":39,"style":39},"-- Upsert\nINSERT INTO users (email, name) VALUES ('a@example.com', 'A')\nON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name;\n\n-- Return the inserted\u002Fupdated row\nUPDATE users SET last_login = now() WHERE id = 42 RETURNING *;\n\n-- JSONB queries\nSELECT * FROM users WHERE metadata->>'plan' = 'pro';\nSELECT * FROM users WHERE metadata @> '{\"beta\": true}';\n\n-- Pagination\nSELECT * FROM users ORDER BY id LIMIT 20 OFFSET 40;\n\n-- Grouped counts\nSELECT date_trunc('day', created_at) AS day, count(*)\nFROM users GROUP BY 1 ORDER BY 1 DESC;\n",[19,1010,1011,1016,1055,1077,1081,1086,1125,1129,1134,1174,1201,1205,1210,1239,1243,1248,1283],{"__ignoreMap":39},[43,1012,1013],{"class":45,"line":46},[43,1014,1015],{"class":65},"-- Upsert\n",[43,1017,1018,1021,1024,1026,1029,1032,1035,1037,1040,1042,1045,1047,1050,1052],{"class":45,"line":69},[43,1019,1020],{"class":83},"INSERT INTO",[43,1022,1023],{"class":509}," users (email, ",[43,1025,895],{"class":83},[43,1027,1028],{"class":509},") ",[43,1030,1031],{"class":83},"VALUES",[43,1033,1034],{"class":509}," (",[43,1036,528],{"class":101},[43,1038,1039],{"class":52},"a@example.com",[43,1041,528],{"class":101},[43,1043,1044],{"class":509},", ",[43,1046,528],{"class":101},[43,1048,1049],{"class":52},"A",[43,1051,528],{"class":101},[43,1053,1054],{"class":509},")\n",[43,1056,1057,1059,1062,1065,1068,1071,1074],{"class":45,"line":96},[43,1058,616],{"class":83},[43,1060,1061],{"class":509}," CONFLICT (email) DO ",[43,1063,1064],{"class":83},"UPDATE",[43,1066,1067],{"class":83}," SET",[43,1069,1070],{"class":83}," name",[43,1072,1073],{"class":101}," =",[43,1075,1076],{"class":509}," EXCLUDED.name;\n",[43,1078,1079],{"class":45,"line":111},[43,1080,553],{"emptyLinePlaceholder":552},[43,1082,1083],{"class":45,"line":129},[43,1084,1085],{"class":65},"-- Return the inserted\u002Fupdated row\n",[43,1087,1088,1090,1092,1095,1098,1101,1103,1106,1109,1112,1114,1117,1120,1123],{"class":45,"line":585},[43,1089,1064],{"class":83},[43,1091,869],{"class":509},[43,1093,1094],{"class":83},"SET",[43,1096,1097],{"class":509}," last_login ",[43,1099,1100],{"class":101},"=",[43,1102,848],{"class":83},[43,1104,1105],{"class":101},"()",[43,1107,1108],{"class":83}," WHERE",[43,1110,1111],{"class":509}," id ",[43,1113,1100],{"class":101},[43,1115,1116],{"class":83}," 42",[43,1118,1119],{"class":509}," RETURNING ",[43,1121,1122],{"class":101},"*",[43,1124,531],{"class":509},[43,1126,1127],{"class":45,"line":608},[43,1128,553],{"emptyLinePlaceholder":552},[43,1130,1131],{"class":45,"line":629},[43,1132,1133],{"class":65},"-- JSONB queries\n",[43,1135,1136,1139,1142,1145,1147,1150,1153,1156,1158,1161,1163,1165,1167,1170,1172],{"class":45,"line":653},[43,1137,1138],{"class":83},"SELECT",[43,1140,1141],{"class":101}," *",[43,1143,1144],{"class":83}," FROM",[43,1146,869],{"class":509},[43,1148,1149],{"class":83},"WHERE",[43,1151,1152],{"class":509}," metadata",[43,1154,1155],{"class":101},"->>",[43,1157,528],{"class":101},[43,1159,1160],{"class":52},"plan",[43,1162,528],{"class":101},[43,1164,1073],{"class":101},[43,1166,522],{"class":101},[43,1168,1169],{"class":52},"pro",[43,1171,528],{"class":101},[43,1173,531],{"class":509},[43,1175,1176,1178,1180,1182,1184,1186,1189,1192,1194,1197,1199],{"class":45,"line":685},[43,1177,1138],{"class":83},[43,1179,1141],{"class":101},[43,1181,1144],{"class":83},[43,1183,869],{"class":509},[43,1185,1149],{"class":83},[43,1187,1188],{"class":509}," metadata @",[43,1190,1191],{"class":101},">",[43,1193,522],{"class":101},[43,1195,1196],{"class":52},"{\"beta\": true}",[43,1198,528],{"class":101},[43,1200,531],{"class":509},[43,1202,1203],{"class":45,"line":690},[43,1204,553],{"emptyLinePlaceholder":552},[43,1206,1207],{"class":45,"line":712},[43,1208,1209],{"class":65},"-- Pagination\n",[43,1211,1212,1214,1216,1218,1220,1223,1225,1228,1231,1234,1237],{"class":45,"line":944},[43,1213,1138],{"class":83},[43,1215,1141],{"class":101},[43,1217,1144],{"class":83},[43,1219,869],{"class":509},[43,1221,1222],{"class":83},"ORDER BY",[43,1224,1111],{"class":509},[43,1226,1227],{"class":83},"LIMIT",[43,1229,1230],{"class":83}," 20",[43,1232,1233],{"class":509}," OFFSET ",[43,1235,1236],{"class":83},"40",[43,1238,531],{"class":509},[43,1240,1241],{"class":45,"line":967},[43,1242,553],{"emptyLinePlaceholder":552},[43,1244,1245],{"class":45,"line":982},[43,1246,1247],{"class":65},"-- Grouped counts\n",[43,1249,1251,1253,1256,1258,1261,1263,1266,1269,1272,1274,1277,1279,1281],{"class":45,"line":1250},16,[43,1252,1138],{"class":83},[43,1254,1255],{"class":509}," date_trunc(",[43,1257,528],{"class":101},[43,1259,1260],{"class":52},"day",[43,1262,528],{"class":101},[43,1264,1265],{"class":509},", created_at) ",[43,1267,1268],{"class":83},"AS",[43,1270,1271],{"class":83}," day",[43,1273,1044],{"class":509},[43,1275,1276],{"class":541},"count",[43,1278,904],{"class":509},[43,1280,1122],{"class":101},[43,1282,1054],{"class":509},[43,1284,1286,1289,1291,1294,1297,1300,1302,1305],{"class":45,"line":1285},17,[43,1287,1288],{"class":83},"FROM",[43,1290,869],{"class":509},[43,1292,1293],{"class":83},"GROUP BY",[43,1295,1296],{"class":83}," 1",[43,1298,1299],{"class":83}," ORDER BY",[43,1301,1296],{"class":83},[43,1303,1304],{"class":83}," DESC",[43,1306,531],{"class":509},[10,1308,1310],{"id":1309},"_6-backup-and-restore","6. Backup and restore",[34,1312,1314],{"className":36,"code":1313,"language":38,"meta":39,"style":39},"# Single database, plain SQL\npg_dump -U app -d appdb > appdb.sql\n\n# Compressed custom format (recommended)\npg_dump -U app -d appdb -Fc -f appdb.dump\n\n# Schema only \u002F a single table\npg_dump -U app -d appdb --schema-only > schema.sql\npg_dump -U app -d appdb -t users -Fc -f users.dump\n\n# Restore\npsql -U app -d appdb \u003C appdb.sql\npg_restore -U app -d appdb --clean --if-exists appdb.dump\npg_restore -U app -d appdb -j 4 appdb.dump        # 4 parallel jobs\n\n# The whole cluster (including roles)\npg_dumpall -U postgres > all.sql\n",[19,1315,1316,1321,1339,1343,1348,1368,1372,1377,1397,1421,1425,1430,1447,1468,1492,1496,1501],{"__ignoreMap":39},[43,1317,1318],{"class":45,"line":46},[43,1319,1320],{"class":65},"# Single database, plain SQL\n",[43,1322,1323,1326,1328,1330,1332,1334,1336],{"class":45,"line":69},[43,1324,1325],{"class":49},"pg_dump",[43,1327,53],{"class":52},[43,1329,56],{"class":52},[43,1331,59],{"class":52},[43,1333,62],{"class":52},[43,1335,481],{"class":101},[43,1337,1338],{"class":52}," appdb.sql\n",[43,1340,1341],{"class":45,"line":96},[43,1342,553],{"emptyLinePlaceholder":552},[43,1344,1345],{"class":45,"line":111},[43,1346,1347],{"class":65},"# Compressed custom format (recommended)\n",[43,1349,1350,1352,1354,1356,1358,1360,1363,1365],{"class":45,"line":129},[43,1351,1325],{"class":49},[43,1353,53],{"class":52},[43,1355,56],{"class":52},[43,1357,59],{"class":52},[43,1359,62],{"class":52},[43,1361,1362],{"class":52}," -Fc",[43,1364,450],{"class":52},[43,1366,1367],{"class":52}," appdb.dump\n",[43,1369,1370],{"class":45,"line":585},[43,1371,553],{"emptyLinePlaceholder":552},[43,1373,1374],{"class":45,"line":608},[43,1375,1376],{"class":65},"# Schema only \u002F a single table\n",[43,1378,1379,1381,1383,1385,1387,1389,1392,1394],{"class":45,"line":629},[43,1380,1325],{"class":49},[43,1382,53],{"class":52},[43,1384,56],{"class":52},[43,1386,59],{"class":52},[43,1388,62],{"class":52},[43,1390,1391],{"class":52}," --schema-only",[43,1393,481],{"class":101},[43,1395,1396],{"class":52}," schema.sql\n",[43,1398,1399,1401,1403,1405,1407,1409,1412,1414,1416,1418],{"class":45,"line":653},[43,1400,1325],{"class":49},[43,1402,53],{"class":52},[43,1404,56],{"class":52},[43,1406,59],{"class":52},[43,1408,62],{"class":52},[43,1410,1411],{"class":52}," -t",[43,1413,758],{"class":52},[43,1415,1362],{"class":52},[43,1417,450],{"class":52},[43,1419,1420],{"class":52}," users.dump\n",[43,1422,1423],{"class":45,"line":685},[43,1424,553],{"emptyLinePlaceholder":552},[43,1426,1427],{"class":45,"line":690},[43,1428,1429],{"class":65},"# Restore\n",[43,1431,1432,1434,1436,1438,1440,1442,1445],{"class":45,"line":712},[43,1433,21],{"class":49},[43,1435,53],{"class":52},[43,1437,56],{"class":52},[43,1439,59],{"class":52},[43,1441,62],{"class":52},[43,1443,1444],{"class":101}," \u003C",[43,1446,1338],{"class":52},[43,1448,1449,1452,1454,1456,1458,1460,1463,1466],{"class":45,"line":944},[43,1450,1451],{"class":49},"pg_restore",[43,1453,53],{"class":52},[43,1455,56],{"class":52},[43,1457,59],{"class":52},[43,1459,62],{"class":52},[43,1461,1462],{"class":52}," --clean",[43,1464,1465],{"class":52}," --if-exists",[43,1467,1367],{"class":52},[43,1469,1470,1472,1474,1476,1478,1480,1483,1486,1489],{"class":45,"line":967},[43,1471,1451],{"class":49},[43,1473,53],{"class":52},[43,1475,56],{"class":52},[43,1477,59],{"class":52},[43,1479,62],{"class":52},[43,1481,1482],{"class":52}," -j",[43,1484,1485],{"class":83}," 4",[43,1487,1488],{"class":52}," appdb.dump",[43,1490,1491],{"class":65},"        # 4 parallel jobs\n",[43,1493,1494],{"class":45,"line":982},[43,1495,553],{"emptyLinePlaceholder":552},[43,1497,1498],{"class":45,"line":1250},[43,1499,1500],{"class":65},"# The whole cluster (including roles)\n",[43,1502,1503,1506,1508,1510,1512],{"class":45,"line":1285},[43,1504,1505],{"class":49},"pg_dumpall",[43,1507,53],{"class":52},[43,1509,120],{"class":52},[43,1511,481],{"class":101},[43,1513,1514],{"class":52}," all.sql\n",[15,1516,1517,1518,1521,1522,739],{},"The custom format (",[19,1519,1520],{},"-Fc",") is compressed and allows selective and parallel restores with ",[19,1523,1451],{},[10,1525,1527],{"id":1526},"_7-performance-and-query-analysis","7. Performance and query analysis",[34,1529,1531],{"className":494,"code":1530,"language":496,"meta":39,"style":39},"EXPLAIN SELECT * FROM users WHERE email = 'a@example.com';\nEXPLAIN (ANALYZE, BUFFERS) SELECT * FROM users WHERE created_at > now() - interval '7 days';\n",[19,1532,1533,1561],{"__ignoreMap":39},[43,1534,1535,1538,1540,1542,1544,1546,1548,1551,1553,1555,1557,1559],{"class":45,"line":46},[43,1536,1537],{"class":509},"EXPLAIN ",[43,1539,1138],{"class":83},[43,1541,1141],{"class":101},[43,1543,1144],{"class":83},[43,1545,869],{"class":509},[43,1547,1149],{"class":83},[43,1549,1550],{"class":509}," email ",[43,1552,1100],{"class":101},[43,1554,522],{"class":101},[43,1556,1039],{"class":52},[43,1558,528],{"class":101},[43,1560,531],{"class":509},[43,1562,1563,1566,1568,1570,1572,1574,1576,1579,1581,1583,1585,1588,1591,1593,1596,1598],{"class":45,"line":69},[43,1564,1565],{"class":509},"EXPLAIN (ANALYZE, BUFFERS) ",[43,1567,1138],{"class":83},[43,1569,1141],{"class":101},[43,1571,1144],{"class":83},[43,1573,869],{"class":509},[43,1575,1149],{"class":83},[43,1577,1578],{"class":509}," created_at ",[43,1580,1191],{"class":101},[43,1582,848],{"class":83},[43,1584,1105],{"class":101},[43,1586,1587],{"class":101}," -",[43,1589,1590],{"class":509}," interval ",[43,1592,528],{"class":101},[43,1594,1595],{"class":52},"7 days",[43,1597,528],{"class":101},[43,1599,531],{"class":509},[15,1601,1602,1603,1606],{},"If you see a ",[19,1604,1605],{},"Seq Scan"," on a large table for a selective query, consider indexing that column.",[15,1608,1609],{},"Running queries and locks:",[34,1611,1613],{"className":494,"code":1612,"language":496,"meta":39,"style":39},"-- Active queries\nSELECT pid, usename, state, now() - query_start AS duration, query\nFROM pg_stat_activity\nWHERE state \u003C> 'idle'\nORDER BY duration DESC;\n\n-- Cancel a query \u002F terminate a connection\nSELECT pg_cancel_backend(12345);\nSELECT pg_terminate_backend(12345);\n\n-- Table and index sizes\nSELECT relname,\n       pg_size_pretty(pg_total_relation_size(relid)) AS total\nFROM pg_catalog.pg_statio_user_tables\nORDER BY pg_total_relation_size(relid) DESC\nLIMIT 10;\n\nSELECT pg_size_pretty(pg_database_size('appdb'));\n",[19,1614,1615,1620,1647,1654,1672,1684,1688,1693,1705,1716,1720,1725,1732,1742,1749,1759,1768,1772],{"__ignoreMap":39},[43,1616,1617],{"class":45,"line":46},[43,1618,1619],{"class":65},"-- Active queries\n",[43,1621,1622,1624,1627,1630,1632,1635,1637,1639,1642,1644],{"class":45,"line":69},[43,1623,1138],{"class":83},[43,1625,1626],{"class":509}," pid, usename, ",[43,1628,1629],{"class":83},"state",[43,1631,1044],{"class":509},[43,1633,1634],{"class":83},"now",[43,1636,1105],{"class":101},[43,1638,1587],{"class":101},[43,1640,1641],{"class":509}," query_start ",[43,1643,1268],{"class":83},[43,1645,1646],{"class":509}," duration, query\n",[43,1648,1649,1651],{"class":45,"line":96},[43,1650,1288],{"class":83},[43,1652,1653],{"class":509}," pg_stat_activity\n",[43,1655,1656,1658,1661,1664,1666,1669],{"class":45,"line":111},[43,1657,1149],{"class":83},[43,1659,1660],{"class":83}," state",[43,1662,1663],{"class":101}," \u003C>",[43,1665,522],{"class":101},[43,1667,1668],{"class":52},"idle",[43,1670,1671],{"class":101},"'\n",[43,1673,1674,1676,1679,1682],{"class":45,"line":129},[43,1675,1222],{"class":83},[43,1677,1678],{"class":509}," duration ",[43,1680,1681],{"class":83},"DESC",[43,1683,531],{"class":509},[43,1685,1686],{"class":45,"line":585},[43,1687,553],{"emptyLinePlaceholder":552},[43,1689,1690],{"class":45,"line":608},[43,1691,1692],{"class":65},"-- Cancel a query \u002F terminate a connection\n",[43,1694,1695,1697,1700,1703],{"class":45,"line":629},[43,1696,1138],{"class":83},[43,1698,1699],{"class":509}," pg_cancel_backend(",[43,1701,1702],{"class":83},"12345",[43,1704,856],{"class":509},[43,1706,1707,1709,1712,1714],{"class":45,"line":653},[43,1708,1138],{"class":83},[43,1710,1711],{"class":509}," pg_terminate_backend(",[43,1713,1702],{"class":83},[43,1715,856],{"class":509},[43,1717,1718],{"class":45,"line":685},[43,1719,553],{"emptyLinePlaceholder":552},[43,1721,1722],{"class":45,"line":690},[43,1723,1724],{"class":65},"-- Table and index sizes\n",[43,1726,1727,1729],{"class":45,"line":712},[43,1728,1138],{"class":83},[43,1730,1731],{"class":509}," relname,\n",[43,1733,1734,1737,1739],{"class":45,"line":944},[43,1735,1736],{"class":509},"       pg_size_pretty(pg_total_relation_size(relid)) ",[43,1738,1268],{"class":83},[43,1740,1741],{"class":509}," total\n",[43,1743,1744,1746],{"class":45,"line":967},[43,1745,1288],{"class":83},[43,1747,1748],{"class":509}," pg_catalog.pg_statio_user_tables\n",[43,1750,1751,1753,1756],{"class":45,"line":982},[43,1752,1222],{"class":83},[43,1754,1755],{"class":509}," pg_total_relation_size(relid) ",[43,1757,1758],{"class":83},"DESC\n",[43,1760,1761,1763,1766],{"class":45,"line":1250},[43,1762,1227],{"class":83},[43,1764,1765],{"class":83}," 10",[43,1767,531],{"class":509},[43,1769,1770],{"class":45,"line":1285},[43,1771,553],{"emptyLinePlaceholder":552},[43,1773,1775,1777,1780,1782,1785,1787],{"class":45,"line":1774},18,[43,1776,1138],{"class":83},[43,1778,1779],{"class":509}," pg_size_pretty(pg_database_size(",[43,1781,528],{"class":101},[43,1783,1784],{"class":52},"appdb",[43,1786,528],{"class":101},[43,1788,1789],{"class":509},"));\n",[10,1791,1793],{"id":1792},"_8-maintenance","8. Maintenance",[34,1795,1797],{"className":494,"code":1796,"language":496,"meta":39,"style":39},"VACUUM (VERBOSE, ANALYZE) users;   -- clean up dead rows, refresh statistics\nANALYZE;                           -- planner statistics for all tables\nREINDEX INDEX CONCURRENTLY idx_users_created_at;\nSHOW max_connections;\nSHOW config_file;\nSELECT version();\n",[19,1798,1799,1813,1821,1832,1837,1842],{"__ignoreMap":39},[43,1800,1801,1804,1807,1810],{"class":45,"line":46},[43,1802,1803],{"class":509},"VACUUM (",[43,1805,1806],{"class":83},"VERBOSE",[43,1808,1809],{"class":509},", ANALYZE) users;   ",[43,1811,1812],{"class":65},"-- clean up dead rows, refresh statistics\n",[43,1814,1815,1818],{"class":45,"line":69},[43,1816,1817],{"class":509},"ANALYZE;                           ",[43,1819,1820],{"class":65},"-- planner statistics for all tables\n",[43,1822,1823,1826,1829],{"class":45,"line":96},[43,1824,1825],{"class":509},"REINDEX ",[43,1827,1828],{"class":83},"INDEX",[43,1830,1831],{"class":509}," CONCURRENTLY idx_users_created_at;\n",[43,1833,1834],{"class":45,"line":111},[43,1835,1836],{"class":509},"SHOW max_connections;\n",[43,1838,1839],{"class":45,"line":129},[43,1840,1841],{"class":509},"SHOW config_file;\n",[43,1843,1844,1846,1849,1851],{"class":45,"line":585},[43,1845,1138],{"class":83},[43,1847,1848],{"class":83}," version",[43,1850,1105],{"class":101},[43,1852,531],{"class":509},[15,1854,1855,1856,1859,1860,1863],{},"Autovacuum is on by default and manual ",[19,1857,1858],{},"VACUUM"," is rarely needed; still, running ",[19,1861,1862],{},"VACUUM ANALYZE"," after bulk deletes\u002Fupdates helps the planner make the right decisions.",[10,1865,1867],{"id":1866},"_9-troubleshooting","9. Troubleshooting",[189,1869,1870,1880],{},[192,1871,1872],{},[195,1873,1874,1877],{},[198,1875,1876],{},"Error",[198,1878,1879],{},"Cause \u002F Fix",[205,1881,1882,1896,1912,1929,1946,1959],{},[195,1883,1884,1889],{},[210,1885,1886],{},[19,1887,1888],{},"FATAL: password authentication failed",[210,1890,1891,1892,1895],{},"Wrong password or the ",[19,1893,1894],{},"pg_hba.conf"," method doesn't match",[195,1897,1898,1903],{},[210,1899,1900],{},[19,1901,1902],{},"FATAL: no pg_hba.conf entry for host",[210,1904,1905,1906,1908,1909],{},"The client IP isn't in ",[19,1907,1894],{},"; add it and run ",[19,1910,1911],{},"SELECT pg_reload_conf();",[195,1913,1914,1919],{},[210,1915,1916],{},[19,1917,1918],{},"Connection refused",[210,1920,1921,1922,1925,1926],{},"The server isn't running or ",[19,1923,1924],{},"listen_addresses"," is only ",[19,1927,1928],{},"localhost",[195,1930,1931,1936],{},[210,1932,1933],{},[19,1934,1935],{},"permission denied for table",[210,1937,1938,1939,1942,1943],{},"Missing ",[19,1940,1941],{},"GRANT SELECT\u002FINSERT ...","; check with ",[19,1944,1945],{},"\\dp table",[195,1947,1948,1953],{},[210,1949,1950],{},[19,1951,1952],{},"too many connections",[210,1954,1955,1956],{},"Use a connection pool in the app (HikariCP, PgBouncer); don't blindly raise ",[19,1957,1958],{},"max_connections",[195,1960,1961,1964],{},[210,1962,1963],{},"A query hangs",[210,1965,1966,1967,1970,1971],{},"Find the blocking query with ",[19,1968,1969],{},"pg_stat_activity"," and ",[19,1972,1973],{},"pg_locks",[10,1975,1977],{"id":1976},"conclusion","Conclusion",[15,1979,1980,1981,1983,1984,1044,1986,1044,1989,1044,1991,1044,1994,1044,1996,1998,1999,2002,2003,2006,2007,2009],{},"Learning ",[19,1982,21],{},"'s meta-commands (",[19,1985,214],{},[19,1987,1988],{},"\\c",[19,1990,244],{},[19,1992,1993],{},"\\d",[19,1995,328],{},[19,1997,338],{},") makes navigating a database faster than any GUI. Add regular backups with ",[19,2000,2001],{},"pg_dump -Fc",", query analysis with ",[19,2004,2005],{},"EXPLAIN ANALYZE"," and live monitoring with ",[19,2008,1969],{},", and most day-to-day PostgreSQL work runs from a single terminal.",[2011,2012,2013],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":39,"searchDepth":69,"depth":69,"links":2015},[2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026],{"id":12,"depth":69,"text":13},{"id":31,"depth":69,"text":32},{"id":183,"depth":69,"text":184},{"id":490,"depth":69,"text":491},{"id":742,"depth":69,"text":743},{"id":1004,"depth":69,"text":1005},{"id":1309,"depth":69,"text":1310},{"id":1526,"depth":69,"text":1527},{"id":1792,"depth":69,"text":1793},{"id":1866,"depth":69,"text":1867},{"id":1976,"depth":69,"text":1977},"2026-11-02","Connecting with psql, meta-commands (\\l, \\dt, \\d), users and privileges, backup\u002Frestore, query analysis and day-to-day maintenance commands.","md",{},"\u002Fen\u002Fblog\u002Fpostgresql-psql-commands",{"title":5,"description":2028},"en\u002Fblog\u002Fpostgresql-psql-commands",[2035,2036,2037],"postgresql","database","guide","\u002Fblog\u002Fpostgresql-psql-commands","LaiVMWENINA9kWF2ceBvFRGDFgRFdyAvDVCLVeyJtcw",[2041,2048,2057],{"path":2042,"title":2043,"description":2044,"date":2045,"tags":2046},"\u002Fen\u002Fblog\u002Fjava-21-features","What's New in Java 21: Virtual Threads, Records and Pattern Matching","The Java 21 LTS features that change day-to-day code the most — virtual threads, records, switch pattern matching, record patterns, sealed classes and sequenced collections.","2026-11-01",[2047,2037],"java",{"path":2049,"title":2050,"description":2051,"date":2052,"tags":2053},"\u002Fen\u002Fblog\u002Fssh-config-and-tunneling","SSH Config, Key Management and Tunneling","Generating ed25519 keys, ssh-agent, shortcuts with ~\u002F.ssh\u002Fconfig, jump hosts, port forwarding (-L, -R, -D) and server-side hardening.","2026-10-31",[2054,2055,2056,2037],"ssh","linux","security",{"path":2058,"title":2059,"description":2060,"date":2061,"tags":2062},"\u002Fen\u002Fblog\u002Fsystemd-service-guide","Writing a Linux Service with systemd","Running an app as a systemd service — unit files, restart policies, environment variables, reading logs with journalctl, and scheduled jobs with timers.","2026-10-30",[2055,2063,2064,2037],"systemd","devops",1793579798042]