CUID Generator logoCUID Generator

CUID Best Practices

Practical tips and patterns for using CUIDs effectively in your applications, from database design to performance optimization.

๐Ÿ—„๏ธ Database Best Practices

Index Your CUID Columns

Always create an index on CUID columns used for lookups. String columns without indexes can be slow for large datasets.

-- PostgreSQL
CREATE INDEX idx_users_id ON users(id);

Use VARCHAR, Not CHAR

CUIDs have fixed lengths, but using VARCHAR is still recommended for flexibility if you later switch between CUID v1 (25 chars) and CUID2 (24 chars).

id VARCHAR(32) PRIMARY KEY

Consider Collation

CUIDs use only lowercase letters and numbers. Using a case-sensitive collation can improve performance slightly, but isn't required.

โšก Performance Optimization

Pre-generate IDs When Possible

For bulk inserts, generate all CUIDs upfront rather than inside the insert loop. This allows for batch validation and optimistic UI.

// Good: Pre-generate
const ids = Array.from({ length: 100 }, () => createId());
// Then use in batch insert

Use Reasonable CUID2 Lengths

While CUID2 supports 2-32 character lengths, stick with the default (24) unless you have specific requirements:

  • โ€ข 2-10 chars: Only for non-critical, high-volume scenarios
  • โ€ข 24 chars: Default, good for most use cases
  • โ€ข 32 chars: Maximum security, rare scenarios

Cache Generator Instances

If using custom CUID2 configurations, create the generator once and reuse:

// Create once at module level
const createShortId = init({ length: 10 });
// Reuse throughout app
const id = createShortId();

โš ๏ธ Common Pitfalls to Avoid

โœ—

Relying on CUID Sort Order

CUID v1 is only roughly sortable by time. For strict ordering, use a separate timestamp column or consider ULID instead.

โœ—

Using CUIDs as Security Tokens

CUID v1 is not cryptographically secure. For tokens, use CUID2 or dedicated token libraries with proper entropy.

โœ—

Assuming Global Uniqueness

While collision probability is extremely low, CUIDs are collision-resistant, not collision-proof. Implement constraints at the database level.

โœ—

Parsing CUIDs as Numbers

CUIDs are strings, not numbers. Never try to convert them to integers or perform arithmetic operations on them.

๐Ÿ—๏ธ Architecture Patterns

Optimistic Updates

CUIDs enable optimistic UI patterns since you can generate the ID before the server confirms the creation:

  1. 1.Generate CUID on the client
  2. 2.Immediately update UI with new item
  3. 3.Send to server in background
  4. 4.Handle errors by reverting if needed

Idempotent Operations

Client-generated CUIDs make operations naturally idempotent. If a request is retried, the same ID prevents duplicate records.

Microservices References

When referencing entities across services, CUIDs work well because they're globally unique without coordination. Store the CUID as a foreign reference string.

๐Ÿงช Testing Considerations

Mock CUIDs in Tests

For deterministic tests, mock the CUID generator:

jest.mock('@paralleldrive/cuid2', () => ({
createId: jest.fn(() => 'test-cuid-123')
}));

Use Real CUIDs in Integration Tests

For integration and E2E tests, use real CUIDs to ensure your system handles the actual format correctly.

โœ… Implementation Checklist

  • โ˜Using CUID2 for new projects (not CUID v1)
  • โ˜Database columns use VARCHAR with appropriate length
  • โ˜Indexes created on CUID columns used for queries
  • โ˜Unique constraints at database level
  • โ˜Validation logic accepts correct CUID format
  • โ˜Using default length (24) unless specifically required
  • โ˜Not relying solely on ID for authorization

Ready to integrate CUID?

Check out our comprehensive code examples to get started in your preferred language in seconds.