---
id: db-postgres-extensions
title: Postgres Extensions — pgvector / TimescaleDB / Citus
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [database, postgres, extensions, vibe-coding]
tech_stack: { language: "PostgreSQL", applicable_to: ["Backend"] }
applied_in: []
aliases: [Postgres extensions, pgvector, TimescaleDB, Citus, PostGIS, pg_cron, pg_partman]
---

# Postgres Extensions

> Postgres = "swiss army knife". **Extension 가 거의 모든 use case**. pgvector / TimescaleDB / Citus / PostGIS / pg_cron 등.

## 📖 핵심 개념
- Extension: SQL + C code module.
- `CREATE EXTENSION`: 활성.
- Cloud RDS / Aurora / Neon = 대부분 지원.
- Self-host = 직접 install.

## 💻 코드 패턴

### 자주 쓰는 extension
```sql
-- Vector
CREATE EXTENSION vector;        -- pgvector

-- Time-series
CREATE EXTENSION timescaledb;    -- TimescaleDB

-- Distributed
CREATE EXTENSION citus;          -- Citus

-- Geo
CREATE EXTENSION postgis;        -- PostGIS

-- Crypto
CREATE EXTENSION pgcrypto;       -- 해시, 암호

-- UUID
CREATE EXTENSION "uuid-ossp";    -- UUID 생성

-- Cron
CREATE EXTENSION pg_cron;        -- DB 안 cron

-- Stats
CREATE EXTENSION pg_stat_statements;  -- query 분석
CREATE EXTENSION auto_explain;         -- slow query log

-- HLL (probabilistic)
CREATE EXTENSION hll;            -- HyperLogLog

-- Trigram (fuzzy search)
CREATE EXTENSION pg_trgm;

-- JSON 강력
CREATE EXTENSION pg_jsonschema;

-- Async / queue
CREATE EXTENSION pgmq;           -- message queue

-- Compression
CREATE EXTENSION pg_lz;
```

### pgvector (vector search)
```sql
CREATE EXTENSION vector;

CREATE TABLE docs (
    id BIGSERIAL,
    content TEXT,
    embedding VECTOR(1536)
);

CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops);

-- Search
SELECT * FROM docs ORDER BY embedding <=> $1::vector LIMIT 5;
```

→ [[DB_pgvector_Production]].

### TimescaleDB (time-series)
```sql
CREATE EXTENSION timescaledb;

CREATE TABLE metrics (
    ts TIMESTAMPTZ NOT NULL,
    device_id TEXT,
    cpu DOUBLE PRECISION
);

SELECT create_hypertable('metrics', 'ts', chunk_time_interval => INTERVAL '1 day');

-- 자동 partition + 압축 + retention
```

→ [[DB_Time_Series_Patterns]].

### Citus (sharding)
```sql
CREATE EXTENSION citus;

SELECT create_distributed_table('orders', 'tenant_id');
-- 자동 sharding by tenant_id
```

→ [[DB_Sharding_Strategies]].

### PostGIS (geo)
```sql
CREATE EXTENSION postgis;

CREATE TABLE places (
    id SERIAL PRIMARY KEY,
    name TEXT,
    location GEOGRAPHY(POINT, 4326)
);

INSERT INTO places (name, location) VALUES (
    'Tower',
    ST_GeographyFromText('POINT(127.0 37.5)')
);

-- 1km 안 가까운
SELECT * FROM places
WHERE ST_DWithin(location, ST_GeographyFromText('POINT(127.0 37.5)'), 1000);

-- 거리
SELECT name, ST_Distance(location, ST_GeographyFromText('POINT(127.0 37.5)')) AS dist
FROM places ORDER BY dist LIMIT 10;
```

### pg_trgm (fuzzy search)
```sql
CREATE EXTENSION pg_trgm;

CREATE INDEX users_name_trgm ON users USING GIN (name gin_trgm_ops);

-- Similar names
SELECT name, similarity(name, 'alice') AS sim
FROM users
WHERE name % 'alice'  -- pg_trgm operator
ORDER BY sim DESC LIMIT 10;

-- Partial match
SELECT * FROM users WHERE name ILIKE '%al%';  -- 빠름 (with trgm index)
```

### pg_cron (scheduled jobs)
```sql
CREATE EXTENSION pg_cron;

-- 매일 오전 9시 cleanup
SELECT cron.schedule('cleanup-old-data', '0 9 * * *', $$
    DELETE FROM events WHERE created_at < NOW() - INTERVAL '90 days'
$$);

-- 매 5분
SELECT cron.schedule('sync-cache', '*/5 * * * *', 'CALL refresh_cache()');

-- List
SELECT * FROM cron.job;

-- Unschedule
SELECT cron.unschedule('cleanup-old-data');
```

→ Application-level cron 대안.

### pgcrypto (encryption)
```sql
CREATE EXTENSION pgcrypto;

-- Hash
SELECT crypt('password', gen_salt('bf'));

-- Verify
SELECT crypt('password', stored_hash) = stored_hash;

-- Random
SELECT gen_random_uuid();
SELECT gen_random_bytes(16);

-- Encrypt
SELECT pgp_sym_encrypt('secret', 'password');
SELECT pgp_sym_decrypt(encrypted, 'password');
```

### pgmq (message queue in PG)
```sql
CREATE EXTENSION pgmq;

SELECT pgmq.create('my_queue');

-- Send
SELECT pgmq.send('my_queue', '{"order_id": 42}');

-- Read (with VT — 30s lock)
SELECT * FROM pgmq.read('my_queue', 30, 1);
-- {msg_id, message, ...}

-- Delete (ack)
SELECT pgmq.delete('my_queue', 1);

-- Archive
SELECT pgmq.archive('my_queue', 1);
```

→ Postgres = light queue. SQS / RabbitMQ alternative.

### pg_stat_statements (query 분석)
```sql
CREATE EXTENSION pg_stat_statements;

-- Top slow queries
SELECT
    query,
    calls,
    total_exec_time / 1000 AS total_seconds,
    mean_exec_time AS avg_ms,
    rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC LIMIT 20;
```

→ [[DB_Postgres_EXPLAIN]].

### auto_explain (slow query log)
```sql
-- postgresql.conf
shared_preload_libraries = 'auto_explain'

ALTER SYSTEM SET auto_explain.log_min_duration = '500ms';
ALTER SYSTEM SET auto_explain.log_analyze = on;
ALTER SYSTEM SET auto_explain.log_buffers = on;
SELECT pg_reload_conf();
```

→ Slow query 자동 EXPLAIN log.

### pg_partman (자동 partition)
```sql
CREATE EXTENSION pg_partman;

SELECT partman.create_parent(
    p_parent_table => 'public.events',
    p_control => 'created_at',
    p_type => 'native',
    p_interval => 'monthly',
    p_premake => 3
);

-- Maintenance (매 시간)
SELECT partman.run_maintenance_proc();
```

→ Automatic partition creation + drop.

### plv8 (JS in DB)
```sql
CREATE EXTENSION plv8;

CREATE FUNCTION my_function(input TEXT)
RETURNS TEXT AS $$
    return input.toUpperCase();
$$ LANGUAGE plv8;

SELECT my_function('hello');  -- 'HELLO'
```

→ JavaScript stored procedure.

### Foreign Data Wrapper (FDW)
```sql
-- Postgres → Postgres
CREATE EXTENSION postgres_fdw;

CREATE SERVER remote_pg
    FOREIGN DATA WRAPPER postgres_fdw
    OPTIONS (host 'remote.example.com', dbname 'app');

CREATE FOREIGN TABLE remote_users
    (id UUID, email TEXT)
    SERVER remote_pg
    OPTIONS (schema_name 'public', table_name 'users');

SELECT * FROM remote_users;
```

→ Postgres → MySQL / S3 / file 도 가능.

### pg_jsonschema (JSON validation)
```sql
CREATE EXTENSION pg_jsonschema;

CREATE TABLE events (
    data JSONB CHECK (jsonschema_is_valid('
        {"type":"object","required":["type"],"properties":{"type":{"type":"string"}}}
    ', data))
);
```

### pgaudit (compliance)
```sql
CREATE EXTENSION pgaudit;

ALTER SYSTEM SET pgaudit.log = 'write,ddl';
SELECT pg_reload_conf();
```

→ Detailed audit log.

### pg_hint_plan (force plan)
```sql
CREATE EXTENSION pg_hint_plan;

/*+ IndexScan(orders orders_user_idx) */
SELECT * FROM orders WHERE user_id = $1;
```

→ Planner hint. Last resort.

### Cloud 의 extension 지원
```
RDS Postgres: 100+ extension.
Aurora: 비슷.
Supabase: pgvector, pg_cron, etc 강.
Neon: pgvector, postgis.
Cloud SQL: 표준 set.

→ Provider docs 검사.
```

### Self-host
```bash
# Docker
docker run -d \
  -e POSTGRES_PASSWORD=secret \
  -p 5432:5432 \
  pgvector/pgvector:pg16

# Or 직접 install
apt install postgresql-16-pgvector
```

### Extension version 관리
```sql
-- 현재 version
SELECT * FROM pg_extension WHERE extname = 'vector';

-- Update
ALTER EXTENSION vector UPDATE TO '0.7.0';

-- Available versions
SELECT * FROM pg_available_extension_versions WHERE name = 'vector';
```

### pg_repack (online table rewrite)
```bash
pg_repack -d mydb -t orders
```

→ VACUUM FULL 의 zero-downtime alternative.

→ [[DB_Vacuum_Autovacuum]].

### Useful 시작 set
```sql
-- 시작 시 활성
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
```

### Combo (modern app)
```
- pgvector (RAG)
- pg_cron (scheduled tasks)
- pgmq (light queue)
- pg_trgm (search)
- pg_stat_statements (monitoring)
- pgaudit (compliance)
```

→ Postgres 만으로 큰 stack 가능.

### Multi-extension query
```sql
-- Vector + cron + JSON
SELECT cron.schedule('embed-new-docs', '*/10 * * * *', $$
    UPDATE docs SET embedding = embed(content)
    WHERE embedding IS NULL
$$);
```

### Custom extension (자체 build)
```c
// my_extension.c
#include "postgres.h"
#include "fmgr.h"

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(my_function);
Datum my_function(PG_FUNCTION_ARGS) {
    int32 arg = PG_GETARG_INT32(0);
    PG_RETURN_INT32(arg * 2);
}
```

→ C 작성 → DB 안 native function.

### Extension as source of truth
```
Cloud-native:
- pgvector + RAG
- pg_cron + jobs
- pgmq + queue
- pg_partman + time-series

→ Postgres = monolith DB. 작은 팀 = 강력.
```

### When NOT to use
```
- 큰 throughput / 분산 — Citus / Yugabyte
- Real-time analytics (PB) — ClickHouse / Druid
- 강력 search — Elasticsearch
- Real-time messaging — Kafka
- 큰 vector (1B+) — Vespa / Milvus
```

### Migration path
```
Start: Postgres + extensions (작은 stack).
Grow: 일부 = 별 system (Kafka, ClickHouse).
End: Specialized stack.

→ Premature specialization X.
   PG 가 90% case 충분.
```

### Backup with extensions
```bash
pg_dump --extensions=all -d mydb > backup.sql

# Or specific
pg_dump --extension=pg_cron --extension=vector -d mydb
```

### Test
```ts
// Test 가 같은 extension 가짐
beforeAll(async () => {
  await db.execute(`CREATE EXTENSION IF NOT EXISTS pg_trgm`);
});
```

## 🤔 의사결정 기준
| 사용 | 추천 extension |
|---|---|
| Vector search | pgvector |
| Time-series | TimescaleDB |
| Sharding | Citus |
| Geo | PostGIS |
| Search | pg_trgm + tsvector |
| Cron | pg_cron |
| Queue | pgmq |
| Crypto | pgcrypto |

## ❌ 안티패턴
- **Cloud 가 안 지원 — extension 가정**: 검사.
- **Major upgrade 시 extension 호환 X**: 검증.
- **Extension 너무 많이**: 의존 복잡.
- **자체 patch — upstream 무시**: 유지 어려움.
- **Production 가 latest minor**: 검증.

## 🤖 LLM 활용 힌트
- Postgres + 5 ~ 10 extension = 큰 stack.
- pgvector + pg_cron + pgmq = mini SaaS.
- Cloud 의 supported list 확인.
- 점진 도입.

## 🔗 관련 문서
- [[DB_pgvector_Production]]
- [[DB_Time_Series_Patterns]]
- [[DB_Sharding_Strategies]]
