Why Your Address Parsing Script Keeps Breaking
I spent three days debugging a customer address validator last year because the input form accepted "Dak" as a valid abbreviation for North Dakota, and my script didn't know what to do with it. The standard two-letter postal abbreviations exist, but the world is full of non-standard data that doesn't care about standards. Understanding the actual system behind state abbreviations matters more than most people realize. The United States Postal Service introduced the two-letter state abbreviations on July 1, 1963. Before that, you might see "Dak." or "Kan." or "W. Va." in old records. The current 50-state set is straightforward if you memorize it, though a few codes are genuinely confusing. Here's the complete list as established by the USPS:
Alabama - AL | Alaska - AK | Arizona - AZ | Arkansas - AR
California - CA | Colorado - CO | Connecticut - CT
Delaware - DE | Florida - FL | Georgia - GA
Hawaii - HI | Idaho - ID | Illinois - IL | Indiana - IN
Iowa - IA | Kansas - KS | Kentucky - KY
Louisiana - LA | Maine - ME | Maryland - MD
Massachusetts - MA | Michigan - MI | Minnesota - MN
Mississippi - MS | Missouri - MO | Montana - MT
Nebraska - NE | Nevada - NV | New Hampshire - NH
New Jersey - NJ | New Mexico - NM | New York - NY
North Carolina - NC | North Dakota - ND | Ohio - OH
Oklahoma - OK | Oregon - OR | Pennsylvania - PA
Rhode Island - RI | South Carolina - SC | South Dakota - SD
Tennessee - TN | Texas - TX | Utah - UT
Vermont - VT | Virginia - VA | Washington - WA
West Virginia - WV | Wisconsin - WI | Wyoming - WY
Us State Abbreviations The 2letter Code That Quietly Runs America
These codes aren't just for mail. They show up in FIPS 5-2 (the federal standard for state identification), in vehicle registration data, in every CRM system ever built, and in government databases going back decades. When you fill out a form that asks for your state as two characters, it's referencing this exact USPS standard. The biggest problem I encounter is that not every territory or associated region uses the same system. Puerto Rico is PR. The US Virgin Islands are VI. Guam is GU. American Samoa is AS. These aren't states, but they appear in address fields all the time. If your system only validates against the 50 states plus DC, all those entries will fail. District of Columbia is DC, which is convenient because it's also the postal abbreviation format, even though it's not technically a state abbreviation. Military addresses use APO, FPO, and DPO with AE (Armed Forces Europe), AP (Armed Forces Pacific), and AA (Armed Forces Americas) as region codes. None of those are state abbreviations, but they behave like them in data processing.
Get the Full Details

Then there's the problem of legacy data. I inherited a database from 1998 where someone had manually typed state names as free text before the two-letter standard became universal. Records contained "Fla.", "La.", "Tex.", "Mass.", and the occasional "NYC" for New York. Converting that required regex patterns that accounted for both the standard and deprecated postal formats that predate 1963.
Technical Implementation
If you're building something that needs to handle state abbreviations, start with a lookup table. Never try to parse state names from free-form text without one. Here's the practical approach I use in Python: I extend this with territory codes and a reverse mapping so I can convert both directions. The reverse mapping is critical for export functions where you need state names but the display format requires two-letter codes. For validation, the most common pitfall is case sensitivity. Postal addresses sometimes come in all lowercase from web forms that don't enforce uppercase. Always normalize to uppercase before comparing against your lookup table. I learned this the hard way when a client's e-commerce platform sent state data as "ca" and "ca" didn't match "CA" in the database. One upper() call fixed it.
ISO 3166-2:US and What It Adds
The international standard ISO 3166-2 uses the exact same two-letter codes for US states, which is unusual consistency. Most countries don't match their ISO codes to their postal abbreviations. The ISO standard also includes Canadian provinces and Mexican states, so if you're working with North American address data internationally, you'll see these codes appear in non-US contexts too. A Canadian "ON" (Ontario) won't conflict with anything, but it's worth noting when building multilingual systems. The Federal Information Processing Standards assign numeric codes to each state. California is 06, Texas is 48, New York is 36. These are used in government data systems, census reporting, and some older federal databases. The FIPS codes and the postal abbreviations serve different purposes and shouldn't be confused, but they're often stored together in the same table. I always keep both in my lookup structures because some legacy systems still reference FIPS numbers and you'll need to join on either one depending on the data source. New York has two airports with similar abbreviations — JFK and Newark (EWR) — but that's aviation, not state data. A more relevant problem is that Kentucky and Kansas both start with K, and in early data entry systems that used single-character prefix matching, this caused real collisions. Not an issue with two-letter codes, but it's worth knowing why the system was designed that way.
Another thing nobody mentions: Delaware's abbreviation is DE, which looks like it could be an abbreviation for "Delaware" but the "E" comes from the end of the word, not the start. That's true for several abbreviations — Tennessee is TN, not TE, because TennesseE doesn't work as an abbreviation. The USPS chose codes that were typically distinct and avoidable in practice, but the pattern isn't perfectly consistent. Don't assume a rule where none exists. Here's a specific edge case I dealt with: a patient registration form at a medical clinic accepted "KENT" as a state value because the dropdown had a custom entry for a vendor's testing account that was never cleaned up. The billing system treated "KENT" as Kentucky and routed claims to the wrong regional office. I added a strict validation layer that rejects any value not in the approved lookup table. Nothing else, no fuzzy matching, no partial string acceptance.
What This System Can't Handle
The two-letter abbreviation system has no mechanism for handling changes in political geography. If a new state were admitted, you'd need to update every database, form, and integration that references the codes. This has happened once — Alaska and Hawaii were added in 1959, and the USPS updated the list in 1963 to include them. Any system built before 1963 that referenced the original 48 states would have been missing those codes entirely. The system also doesn't distinguish between the District of Columbia and any state, even though DC has a different legal status. It's in the same list with the same format. If your application needs to enforce state-specific tax rules or regulatory compliance, you'll need a separate flag for DC rather than treating it identically to the state codes. For address validation beyond what the USPS provides, you should pair the two-letter codes with ZIP code lookup. The abbreviation tells you the state, but it doesn't validate the city or ZIP. A valid combination like "CA 90210" is fine, but "CA 00000" won't produce a delivery error because the state code is correct — the ZIP is what matters for routing. USPS address validation APIs handle this layer separately.