Use a text type for E.164
Store the canonical number in a text or varchar column large enough for the plus sign and the international value. Numeric columns discard representation, encourage arithmetic that has no meaning and complicate values outside local assumptions.
A practical schema can include phone_e164, phone_region, phone_extension, verified_at and verification_method. Do not overload one nullable column with all of those meanings.
Normalize before uniqueness checks
Raw strings such as (202) 555-0123 and +1 202 555 0123 can identify the same destination. Parse with country context, normalize, then apply a unique index only if your product truly requires one account per number. Family, office and recycled numbers can make global uniqueness a harmful business rule.
Separate verification from validity
A successful OTP records that someone controlled a delivery route at a point in time. It does not permanently establish identity or future ownership. Store verification time and purpose, expire high-risk claims and avoid presenting a library validation result as ownership.
Protect contact data
- Restrict access to full phone values.
- Encrypt sensitive columns or the containing datastore where appropriate.
- Mask values in logs and analytics.
- Keep retention tied to a documented purpose.
- Audit exports and support-tool access.
Use generated fixtures from the country format dataset instead of copying production contact data into development.
Format only at presentation time
Render a national or international display from the canonical value and the viewer's context. Do not rewrite stored identity merely because a UI changes punctuation. The international structure follows ITU-T E.164.