c0dec0de / snowflake-id
A PHP library for generating Snowflake IDs
Installs: 6
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/c0dec0de/snowflake-id
Requires
- php-64bit: >=8.4
Requires (Dev)
- ext-redis: *
- friendsofphp/php-cs-fixer: dev-master
- mockery/mockery: 2.0.x-dev
- php-mock/php-mock-phpunit: dev-master
- phpbench/phpbench: 84.x-dev
- phpstan/phpstan: 2.1.x-dev
- phpunit/phpunit: 12.3.x-dev
- predis/predis: dev-main
- rector/rector: dev-main
- vimeo/psalm: ^7.0@dev
README
A PHP library for generating Snowflake IDs
📦 Installation
The recommended way to install the package is via Composer:
composer require c0dec0de/snowflake-id
❄️ What is a Snowflake ID?
A Snowflake ID is a unique 64-bit integer used in distributed systems to generate sortable, collision-resistant identifiers without a central source. Originally developed by Twitter, the format has been adopted by platforms like Discord, Instagram, and Mastodon.
Each Snowflake originally consists of:
- 41 bits for a timestamp (in milliseconds since a custom epoch)
- 10 bits for a machine ID
- 12 bits for a sequence number (allowing multiple IDs per millisecond) This structure ensures that IDs are unique, time-sortable, and can be generated at high throughput across distributed nodes.
This library follows the original Snowflake structure closely but splits the 10 bits originally allocated for the machine ID into two parts, using the following layout:
- 41 bits for a timestamp (milliseconds since a custom epoch)
- 5 bits for a datacenter ID
- 5 bits for a worker (machine) ID
- 12 bits for a sequence number (allowing multiple IDs per millisecond)
This split provides finer control over deployment in multi-datacenter environments.
Benefits of Snowflakes
- Distributed-safe 64bit unique human-readable ID generation
- Time sortable by design
- 64-bit integer output: smaller index, faster joins compared to 128-bit alternatives such a UUIDs or ULIDs
Usage
🧙 Let's play with Snowflakes
You can start by generating your first Snowflake ID by running this code:
<?php declare(strict_types=1); require_once 'vendor/autoload.php'; use C0dec0de\Snowflake\Snowflake; $snowflakeIDIntType = Snowflake::int(); var_dump($snowflakeIDIntType); // e.g., int(195302773577621504)
Or use the method that generates and returns a Snowflake ID as a string
<?php declare(strict_types=1); require_once 'vendor/autoload.php'; use C0dec0de\Snowflake\Snowflake; $snowflakeIDStringType = Snowflake::string(); var_dump($snowflakeIDStringType); // e.g., string(195302773577621504)
⚠️ Best Practice
For production use, always explicitly provide the datacenterId, workerId, and store arguments when calling Snowflake::int() or Snowflake::string().
Providing these values ensures:
- Predictable and unique ID generation
- Safe operation across multiple machines and processes
- Use of a production-grade store like
RedisStorefor concurrency safety
By default, if you omit these arguments:
- The library will assign random values for
datacenterIdandworkerId - It will fall back to
InMemoryStore, which is not safe for concurrent or multi-process environments
✅ Tip: Calling these methods without arguments is perfectly fine for prototyping, testing, or learning the API — just avoid it in real-world deployments where uniqueness and reliability are critical.
✅ Generating Globally Unique Snowflake IDs in Production
To reliably generate collision-free Snowflake IDs across multiple processes, machines, and datacenters, follow these production-grade recommendations:
- 🔧 Assign a unique
datacenterIdto each datacenter. - 🧩 Assign a unique
workerIdto each machine within the same datacenter. - 🛡️ Use
RedisStoreas thestoreargument to ensure safe operation in concurrent and multi-process environments (e.g., high request volume, parallel workers). - ⏱️ Synchronize system clocks via NTP (Network Time Protocol) on all machines to avoid clock drift, which can cause inconsistencies or ID collisions.
✅ With this setup, your Snowflake ID generation is fully production-ready — scalable, reliable, and globally unique.
Setup Steps
- Configure your
workerIdanddatacenterId. For example, assign a uniqueworkerIdto each machine within the samedatacenterId. - Instantiate
RedisStore, passing in a properly configured Redis client (phpredisorpredis/predis).
This approach guarantees safe, scalable ID generation across distributed environments.
<?php declare(strict_types=1); require_once 'vendor/autoload.php'; use C0dec0de\Snowflake\Sequence\Store\RedisStore; use C0dec0de\Snowflake\Sequence\Store\StoreInterface; use C0dec0de\Snowflake\Snowflake; /** * Instantiate and configure your preferred Redis client (phpredis or predis). */ $client = new Redis(); $client->connect( host: 'keyval', port: 6379, timeout: 2.5, ); /** * Pass the Redis client instance to RedisStore. */ $redisStore = new RedisStore($client); /** * Generate a Snowflake ID with: * * @param StoreInterface|null $store - Pass the configured RedisStore instance; if null, InMemoryStore is used. * @param int|null $datacenterId - Unique datacenter ID (configure per datacenter). * @param int|null $workerId - Unique worker/machine ID within the datacenter. */ $snowflakeIDIntType = Snowflake::int( store: $redisStore, datacenterId: 1, workerId: 1, ); var_dump($snowflakeIDIntType); // e.g., int(195302773577621504)
This is the gold standard configuration for using the library to generate Snowflake IDs, guaranteeing zero collisions out of the box without any additional setup.
Customization
This library is designed for flexibility and extensibility. You can provide your own implementations of several core components.
Sequence Stores
The library includes the following built-in sequence stores:
InMemoryStore– ⚠️ Not safe for concurrent use. Stores sequence state in local process memory. May lead to ID collisions under high concurrency (in multi-process environments).RedisStore– ✅ Production-ready. Stores sequence state in Redis. Safe for concurrent and multi-process usage. Supports bothphpredisandpredisclients.
To support other Redis clients or wrappers, you can implement your own adapter by extending the RedisConnectionAdapterInterface.
Both InMemoryStore and RedisStore implements the StoreInterface. You can create your own custom stores by implementing this interface.
ID Structure
The library comes with a standard Snowflake structure implementation:
StdStructure– Twitter-like Snowflake layout:- 41 bits for timestamp
- 5 bits for datacenter ID
- 5 bits for worker ID
- 12 bits for sequence
- Custom epoch: 2024-01-01 00:00:00
StdStructure implements the StructureInterface. You can create your own custom structure by implementing this interface.
Sequence Generators
Available sequence generation strategies:
StdSequenceGenerator– Default and recommended. Generates a sequence counter per tick, starting from 0 up to the max allowed by the structure (e.g., 4095 for 12-bit sequence capacity).PidBasedSequenceGenerator– ⚠️ Unsafe and experimental. Generates sequence values based on the process ID (PID). Designed for fun and testing only. May cause collisions and should not be used in production.
All sequence generators implement the SequenceGeneratorInterface, allowing you to define and plug in your own strategy if needed.
-
SequenceGeneratorInterface– Defines the strategy for generating the sequence number within the same tick(millisecond). You can implement custom logic based on your performance, concurrency, or reset requirements. -
StoreInterface(Sequence Store) – Responsible for storing the last sequence number and the last tick(timestamp). This allows you to plug in different storage mechanisms (e.g., in-memory, Redis, file-based) depending on your environment.
⚠️ Note:
By default (if not explicitly configured), the library uses anInMemoryStoreduring the ID generation process.
This store is not thread-safe and may lead to ID collisions in multi-process or concurrent environments,
as tick-sequence data remains isolated within the current process's memory and is not synchronized across processes.
For production use, consider configuring a persistent and thread-safe RedisStore.
Versioning
This library follows Semantic Versioning.
See CHANGELOG.md for release history.
Contributing
Pull requests are welcome. Please see CONTRIBUTING.md for details and code style guidelines.
License
MIT. See LICENSE file for details.
Credits
Inspired by Twitter(X)'s Snowflake algorithm.