snowflake

Snowflake-style 64-bit ID generator and sequence utilities for PostgreSQL

Overview

PackageVersionCategoryLicenseLanguage
snowflake2.5.0FUNCPostgreSQLC
IDExtensionBinLibLoadCreateTrustRelocSchema
4590snowflakeNoYesNoYesNoNosnowflake
Relatedspock lolor

works on pgedge kernel fork. Set snowflake.node (1..1023) before using snowflake.nextval().

Version

TypeRepoVersionPG VerPackageDeps
EXTPIGSTY2.5.01817161514snowflake-
RPMPIGSTY18.41817161514pgedge-$v-
DEBPIGSTY18.41817161514pgedge-$v-
OS / PGPG18PG17PG16PG15PG14
el8.x86_64N/A
el8.aarch64N/A
el9.x86_64N/A
el9.aarch64N/A
el10.x86_64N/A
el10.aarch64N/A
d12.x86_64N/A
d12.aarch64N/A
d13.x86_64N/A
d13.aarch64N/A
u22.x86_64N/A
u22.aarch64N/A
u24.x86_64N/A
u24.aarch64N/A
u26.x86_64N/A
u26.aarch64N/A

Build

You can build the RPM / DEB packages for snowflake using pig build:

pig build pkg snowflake         # build RPM / DEB packages

Install

You can install snowflake directly. First, make sure the PGDG and PIGSTY repositories are added and enabled:

pig repo add pgsql -u          # Add repo and update cache

Install the extension using pig or apt/yum/dnf:

pig install snowflake;          # Install for current active PG version
pig ext install -y snowflake -v 18  # PG 18
pig ext install -y snowflake -v 17  # PG 17
pig ext install -y snowflake -v 16  # PG 16
pig ext install -y snowflake -v 15  # PG 15
dnf install -y pgedge-18       # PG 18
dnf install -y pgedge-17       # PG 17
dnf install -y pgedge-16       # PG 16
dnf install -y pgedge-15       # PG 15
apt install -y pgedge-18   # PG 18
apt install -y pgedge-17   # PG 17
apt install -y pgedge-16   # PG 16
apt install -y pgedge-15   # PG 15

Create Extension:

CREATE EXTENSION snowflake;

Usage

Sources:

snowflake generates distributed bigint identifiers from a timestamp, a per-node identifier, and an in-millisecond counter. Existing PostgreSQL sequences can be converted so table defaults continue using nextval(...) while producing Snowflake IDs.

CREATE EXTENSION snowflake;

Configuration

Assign every writable node a distinct identifier in postgresql.conf, then reload PostgreSQL:

snowflake.node = 1

Reusing a node identifier on concurrently writable servers can generate duplicate IDs.

Convert a Sequence

Create a normal PostgreSQL sequence, then convert its definition. Existing values in referencing columns are not rewritten.

CREATE TABLE orders (
  id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  payload jsonb NOT NULL
);

SELECT snowflake.convert_sequence_to_snowflake(
  pg_get_serial_sequence('orders', 'id')::regclass
);

INSERT INTO orders (payload) VALUES ('{"status":"new"}');
SELECT id, snowflake.format(id) FROM orders;

Functions

FunctionDescription
snowflake.nextval([sequence regclass])Generate the next Snowflake ID (uses internal sequence if none specified)
snowflake.currval([sequence regclass])Return the current value of the sequence
snowflake.get_epoch(snowflake int8)Extract the timestamp as epoch (seconds since 2023-01-01)
snowflake.get_count(snowflake int8)Extract the count part (resets per millisecond)
snowflake.get_node(snowflake int8)Extract the node identifier
snowflake.format(snowflake int8)Return a JSONB with node, ts, and count fields

Examples

-- Generate a snowflake ID
SELECT snowflake.nextval();
-- 136169504773242881

-- Use an already converted named sequence
SELECT snowflake.nextval('orders_id_seq'::regclass);

-- Extract components
SELECT snowflake.get_epoch(136169504773242881);
-- 1704996539.845

SELECT to_timestamp(snowflake.get_epoch(136169504773242881));
-- 2024-01-11 13:08:59.845-05

SELECT snowflake.get_node(136169504773242881);
-- 1

SELECT snowflake.format(136169504773242881);
-- {"id": 1, "ts": "2024-01-11 13:08:59.845-05", "count": 0}

-- Use as default column
CREATE TABLE direct_ids (
  id int8 DEFAULT snowflake.nextval() PRIMARY KEY,
  data text
);

Review and Upgrade

Review converted table defaults with psql \d+ or the PostgreSQL catalogs. They should call snowflake.nextval(...) rather than the original nextval(...):

SELECT table_schema, table_name, column_name, column_default
FROM information_schema.columns
WHERE column_default LIKE 'snowflake.nextval(%';

Version 2.5.0 fixes dump/restore of converted sequences whose MAXVALUE was left at the normal bigint maximum. It also repairs conversion SQL for affected sequences and adds PostgreSQL 18 support.

Caveats

  • Conversion changes the sequence definition, not IDs already stored in table rows.
  • A Snowflake generator can emit at most 4096 counter values per millisecond. Do not configure a sequence increment above 4096.
  • Keep the node identifier stable and unique for the lifetime of concurrent writers; record it as part of cluster provisioning and failover procedures.
  • Install the same extension version on every node before logical replication or rolling changes involving converted sequence definitions.

Last Modified 2026-07-23: update extension list to 555 (d81fc56)