Skip to content

Sqid

Sqids (pronounced “squids”) is the successor to Hashids, providing a way to encode integers into short, URL-safe strings. Unlike random IDs, Sqids are deterministic and reversible - the same numbers always produce the same output, and you can decode them back to the original values.

FeatureSqidUUIDAuto-increment
ReversibleYesNoN/A
DeterministicYesNoN/A
Short~6 chars36 charsVaries
Hides DB IDsYesYesNo
Sequential guessingProtectedProtectedVulnerable

Use cases:

  • Public-facing IDs that hide database auto-increment values
  • URL shortening
  • Share/invite codes
  • Order/confirmation numbers
use Cline\Mint\Mint;
// Encode a single number
$sqid = Mint::sqid()->encodeNumber(42);
echo $sqid->toString(); // "8QRLaD"
// Or use encode with array
$sqid = Mint::sqid()->encode([42]);
echo $sqid->toString(); // "8QRLaD"
// Encode multiple numbers into one string
$sqid = Mint::sqid()->encode([1, 2, 3]);
echo $sqid->toString(); // "86Rf07"
// Useful for composite keys
$sqid = Mint::sqid()->encode([$userId, $postId]);
echo $sqid->toString(); // "xkJ7y2"
// Generate based on timestamp + counter (for unique IDs)
$sqid = Mint::sqid()->generate();
echo $sqid->toString();
// Decode back to numbers
$numbers = Mint::sqid()->decode('86Rf07');
// [1, 2, 3]
$numbers = Mint::sqid()->decode('8QRLaD');
// [42]
// Invalid Sqids return empty array
$numbers = Mint::sqid()->decode('invalid');
// []

Pad short Sqids to a minimum length:

// Without minimum length
$sqid = Mint::sqid()->encodeNumber(1);
echo $sqid->toString(); // "Uk"
// With minimum length
$sqid = Mint::sqid()->minLength(10)->encodeNumber(1);
echo $sqid->toString(); // "kRbLa23Uk9"

Customize the characters used:

// Lowercase only
$sqid = Mint::sqid()
->alphabet('abcdefghijklmnopqrstuvwxyz')
->encode([42]);
echo $sqid->toString(); // "xqyvzp"
// Numeric only
$sqid = Mint::sqid()
->alphabet('0123456789')
->encode([42]);
echo $sqid->toString(); // "924610"

Prevent generation of specific words:

$sqid = Mint::sqid()
->blocklist(['bad', 'word'])
->encode([123]);
// If output would contain "bad" or "word",
// alphabet is shuffled to produce different output
$sqid = Mint::sqid()
->alphabet('abcdefghijklmnopqrstuvwxyz0123456789')
->minLength(8)
->blocklist(['spam', 'test'])
->encode([42]);

Configure defaults in config/mint.php:

return [
'sqid' => [
'alphabet' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
'min_length' => 0,
'blocklist' => [],
],
];
if (Mint::sqid()->isValid($input)) {
$numbers = Mint::sqid()->decode($input);
}
// Validates characters are in the alphabet
// Parse into Sqid object (without decoding)
$sqid = Mint::sqid()->parse('86Rf07');
echo $sqid->toString(); // "86Rf07"
// In Model
class Post extends Model
{
public function getPublicIdAttribute(): string
{
return Mint::sqid()->encodeNumber($this->id)->toString();
}
public static function findByPublicId(string $publicId): ?self
{
$decoded = Mint::sqid()->decode($publicId);
return $decoded ? self::find($decoded[0]) : null;
}
}
// In Controller
Route::get('/posts/{publicId}', function (string $publicId) {
$post = Post::findByPublicId($publicId);
if (!$post) {
abort(404);
}
return $post;
});
class UrlShortener
{
public function shorten(string $url): string
{
$link = ShortLink::create(['url' => $url]);
return Mint::sqid()->minLength(6)->encodeNumber($link->id)->toString();
}
public function resolve(string $code): ?string
{
$decoded = Mint::sqid()->minLength(6)->decode($code);
if (!$decoded) {
return null;
}
return ShortLink::find($decoded[0])?->url;
}
}
class Order extends Model
{
public function getConfirmationNumber(): string
{
// Encode multiple values for composite uniqueness
return Mint::sqid()
->minLength(10)
->alphabet('ABCDEFGHJKLMNPQRSTUVWXYZ23456789')
->encode([$this->id, $this->user_id])
->toString();
}
}
class Document extends Model
{
public function generateShareCode(): string
{
// Include document ID and expiry timestamp
$expiryTimestamp = now()->addDays(7)->timestamp;
return Mint::sqid()
->encode([$this->id, $expiryTimestamp])
->toString();
}
public static function findByShareCode(string $code): ?self
{
$decoded = Mint::sqid()->decode($code);
if (count($decoded) !== 2) {
return null;
}
[$id, $expiry] = $decoded;
if ($expiry < now()->timestamp) {
return null; // Expired
}
return self::find($id);
}
}

Sqids are not encrypted - they are obfuscated. Do not use them for security-sensitive data. Anyone with the same configuration can decode them.

// These are equivalent - no security
Mint::sqid()->decode('86Rf07'); // Anyone can do this

Encoding and decoding must use the same configuration:

// Encode with config A
$encoded = Mint::sqid()->minLength(10)->encode([42])->toString();
// Decode with config A - works
$numbers = Mint::sqid()->minLength(10)->decode($encoded); // [42]
// Decode with config B - fails
$numbers = Mint::sqid()->minLength(5)->decode($encoded); // []

Sqids only work with non-negative integers:

Mint::sqid()->encode([0, 1, 2]); // Works
Mint::sqid()->encode([-1]); // Error
Mint::sqid()->encode([1.5]); // Error
MethodDescription
alphabet(string $alphabet)Set custom character set (min 3 chars)
minLength(int $length)Set minimum output length
blocklist(array $words)Set words to avoid in output
generate()Generate unique Sqid (timestamp-based)
encode(array $numbers)Encode array of integers
encodeNumber(int $number)Encode single integer
decode(string $value)Decode to array of integers
parse(string $value)Parse into Sqid object
isValid(string $value)Validate format
MethodReturnsDescription
toString()stringString representation
getTimestamp()nullAlways null
isSortable()boolAlways false