Canadian Postal Code Validator

Check the format of a Canadian postal code and see which province or territory it is consistent with. Paste one, or a whole column.

What this validator checks, and what it cannot

It checks two things. First, that a postal code is structurally valid: the right shape, the right letters in the right positions, and none of the letters Canada Post does not use. Second, that its first letter is one actually assigned to a given province or territory, if you tell it which one to expect.

It cannot tell you whether a postal code exists. There is no lookup here against Canada Post’s address data, because that data is licensed commercially and cannot be redistributed — so this site holds none of it. A code can pass every check on this page and still not be in service.

That distinction matters more than it sounds. "Valid" and "real" are different questions, and a validator that quietly answers the first while a user believes it answered the second is worse than one that refuses. If you need to know whether an address receives mail, you need an address verification service with a licence. This is a format checker.

The format

A Canadian postal code is six characters in the pattern ANA NAN — letter, digit, letter, space, digit, letter, digit. It is a string, always. It is never a number, it is never stored without its space in a display, and it is never sorted numerically.

The first three characters are the Forward Sortation Area, or FSA. The last three are the Local Delivery Unit, or LDU.

K 1 A   0 B 1
│ │ │   │ │ │
│ │ │   │ │ └─ LDU digit
│ │ │   │ └─── LDU letter
│ │ │   └───── LDU digit
│ │ └───────── FSA letter
│ └─────────── FSA digit: 0 = rural area, 1-9 = urban area
└───────────── postal district letter — identifies the province or territory

Edge case 1 — the excluded letters are not one list, they are two rules

D, F, I, O, Q and U are not used in any position. That much is usually stated correctly.

W and Z are different: they are not used in the FIRST position, but they are perfectly valid in the third and fifth. M4W and H2Z are real forward sortation areas. A validator that rejects W and Z everywhere will reject legitimate Toronto and Montréal postal codes.

This trips people up because some summaries list all eight letters together under a heading like "letters not in use", which reads as a single rule about every position. It is two rules, and conflating them produces a validator that is wrong in a way its author will not notice until a user complains.

PositionPermittedExcluded
1 (district)A B C E G H J K L M N P R S T V X YD F I O Q U W Z
3 and 5A B C E G H J K L M N P R S T V W X Y ZD F I O Q U
2, 4, 60-9—

Edge case 2 — X does not identify a region

Northwest Territories and Nunavut share the postal district X. So a postal code beginning with X is consistent with either, and nothing in the code distinguishes them. No amount of parsing narrows it down.

Every other postal district letter maps to exactly one province or territory, which is why this one is so easy to miss: a lookup table built by hand works for twelve regions and silently returns the wrong answer for the thirteenth. Worse, it looks correct in testing unless your fixtures happen to contain both territories.

This validator returns an array of inferred regions and never picks one. For an X code you get both, flagged as ambiguous. If you are building a postal-code-to-region function, that is the shape it should have too — and the reason to store a region code alongside a postal code rather than deriving one from the other.

Edge case 3 — rural or urban is a property of the area, not of an address

The second character marks the forward sortation area as rural (0) or urban (1-9). It is easy to read that as a fact about a particular address, and it is not.

Nunavut settles the point better than any explanation. The territory has exactly three forward sortation areas — X0A, X0B and X0C — and every one carries 0 in the second position. Nunavut has no urban FSA at all. So every address in Iqaluit, a territorial capital with numbered streets and door-to-door delivery, carries a rural-marked postal code. There is no other kind available.

Anything that reads a 0 as "this is a rural address" therefore misclassifies an entire territory, including its capital. Iqaluit is not an exception to the rule — it is the case that shows the inference was never sound anywhere. The marker describes how Canada Post organises the sortation area, and nothing about the delivery point of any individual address inside it.

Northwest Territories next door makes the contrast: X0E, X0G and X1A, of which only X1A — Yellowknife — is urban-marked. Two neighbouring territories, one with a single urban FSA and one with none.

This project got the same thing backwards in the other direction at first: it derived the marker from the delivery type it was generating, which produced internally consistent synthetic data and encoded an assumption that does not hold for real postal codes. Since the FSAs became real that is no longer possible — a civic Iqaluit address now gets X0A, X0B or X0C, because those are the only codes there are.

A regex, and why it is not enough

This pattern enforces the format and the position-specific letter rules, including the W and Z distinction. It is the strictest a regular expression can usefully be here.

/^[ABCEGHJKLMNPRSTVXY][0-9][ABCEGHJKLMNPRSTVWXYZ] ?[0-9][ABCEGHJKLMNPRSTVWXYZ][0-9]$/i

What the regex cannot do

So the regex is a first gate, not the whole check. Use it to reject obvious junk cheaply, then normalise, then look up the region, then compare against whatever else you collected.

Accepted input formats

All of these normalise to K1A 0B1 and are treated as valid. Rejecting any of them is a bug in a form, not a defence.

InputNormalises toWhy accept it
K1A 0B1K1A 0B1canonical
k1a 0b1K1A 0B1case is not meaningful
K1A0B1K1A 0B1the space is positional, not informational
k1a0b1K1A 0B1both at once
K1A-0B1K1A 0B1a common way to type it, unambiguous
k1a 0b1 K1A 0B1pasted from a spreadsheet

Questions

Does this tell me whether a postal code is real?

No. It tells you whether a postal code is well-formed and whether its first letter matches a province you name. Confirming that a code is in service requires Canada Post address data, which is licensed commercially and which this site does not hold.

Why does an X postal code return two regions?

Because Northwest Territories and Nunavut share the X postal district, so the code is genuinely consistent with both. Returning one would be a guess presented as an answer.

Is W really valid in a postal code?

Yes, in the third and fifth positions — 64 forward sortation areas carry W in the third position, and 49 carry Z. W and Z are excluded only from the first position. The letters excluded everywhere are D, F, I, O, Q and U.

Should I store a postal code as a string or strip the space?

Store it as a string, and keep the space in anything a person reads. Strip it if you like for indexing or comparison, but normalise on the way in rather than storing two different shapes and hoping the comparison catches both.

Can I use the second character to tell whether an address is rural?

No. It marks the sortation area as rural or urban, which is a property of the area rather than of any individual address inside it. The clearest proof is Nunavut: its only forward sortation areas are X0A, X0B and X0C, all rural-marked, so every address in Iqaluit carries one — a territorial capital where no urban-marked code exists. Rural-marked areas contain street addresses, and urban-marked areas contain post office boxes.

Related

Everything this site generates is synthetic, produced for development, QA, testing, demos and staging. The records do not represent real people, and the addresses are not verified deliverable addresses.