Skip to content

DuckDB vs PostgreSQL

Both extensions share the same core functionality but have platform-specific features.

FeatureDuckDBPostgreSQL
Core Type
monetary typeYesYes
Integer storage (no float errors)YesYes
70+ currenciesYesYes
Currency symbols parsingYesYes
Banker’s roundingYesYes
Operators
Arithmetic (+, -, *, /)YesYes
Comparison (=, <, >, etc.)YesYes
Currency mismatch errorsYesYes
Aggregates
SUMYesYes
AVGYesYes
MIN/MAXYesYes
Country/Currency
currency_for_country()YesYes
countries_for_currency()YesYes
Exchange Rates
ECB ratesYesNo
10 exchange rate sourcesYesNo
Arrow operator (->>)YesNo
Currency macros (USD, EUR)YesNo
Historical conversionsYesNo
Installation
Community extensionYesBuild from source
WASM supportYesNo
  • Analytics workloads: Columnar storage, vectorized execution
  • WASM/browser: Interactive documentation, client-side analytics
  • Exchange rates: Built-in functions for 10 sources
  • Currency conversion: Arrow operator and macros for easy conversions
  • Data pipelines: Read/write Parquet, CSV, JSON directly
  • Production OLTP: Mature, battle-tested for transactional workloads
  • Existing PostgreSQL: Add monetary support to existing databases
  • Full SQL compliance: Complete SQL standard support
  • Ecosystem: Works with all PostgreSQL tools (pgAdmin, psql, etc.)
  • Extensions: Combine with other PostgreSQL extensions

Most code is portable between platforms:

-- Type creation
SELECT '100 EUR'::monetary;
-- Arithmetic
SELECT '100 EUR'::monetary + '50 EUR'::monetary;
SELECT '100 EUR'::monetary * 2;
-- Comparisons
SELECT '100 EUR'::monetary > '50 EUR'::monetary;
-- Accessors
SELECT monetary_amount('99.99 EUR'::monetary);
SELECT monetary_currency('100 USD'::monetary);
-- Country/currency lookup
SELECT currency_for_country('US');
SELECT countries_for_currency('EUR');
-- Aggregates
SELECT SUM(amount) FROM orders WHERE monetary_currency(amount) = 'EUR';
-- Exchange rate functions
SELECT * FROM ecb_exchange_rates();
SELECT * FROM twelvedata_exchange_rates();
-- Currency conversion
SET monetary_exchange_table = 'exchange_rates';
SELECT '100 EUR'::monetary ->> 'USD';
SELECT USD('100 EUR'::monetary);
-- Historical conversion
SELECT USD_AT('100 EUR'::monetary, '2025-01-15');
-- Export from PostgreSQL
COPY (SELECT * FROM transactions) TO '/tmp/transactions.csv' CSV HEADER;
-- Import to DuckDB
CREATE TABLE transactions AS
SELECT * FROM read_csv('/tmp/transactions.csv');
-- Export from DuckDB
COPY transactions TO '/tmp/transactions.csv' (HEADER);
-- Import to PostgreSQL
\copy transactions FROM '/tmp/transactions.csv' CSV HEADER
AspectDuckDBPostgreSQL
Bulk analyticsExcellent (columnar)Good
Single-row OLTPModerateExcellent
Concurrent writesLimitedExcellent
Memory usageHigher (columnar)Lower
Startup timeFaster (embedded)Slower (server)

Both extensions share C++ code in the shared/ directory:

  • monetary.hpp/cpp - Core Monetary struct
  • currency.hpp/cpp - Currency enum and metadata
  • country.hpp/cpp - Country-to-currency mapping
  • parser.hpp/cpp - String parsing logic

This ensures consistent behavior across both platforms.