postgres / now

now() is not wall-clock time.

It is shorthand for transaction_timestamp(), fixed when the transaction begins.

That is usually what you want. Every now() in the same transaction returns the same value, so audit columns line up:

INSERT INTO docs (
  title, summary, created_at, updated_at
) VALUES (
  $1, $2, now(), now()
);

Two calls, one timestamp. Multi-row inserts and batch updates get the same guarantee.

The footgun is a freshness check inside a long transaction. A typical cooldown query:

SELECT
  1
FROM
  jobs
WHERE
  name = $1
  AND finished_at > now() - '3 days'::interval
LIMIT 1;

Fine on its own. Inside a retry loop that stays in one BEGIN ... COMMIT, now() never advances and the cooldown window is frozen.

Reach for clock_timestamp() when you need real elapsed time inside a transaction. It reads the wall clock on each call.

← All articles