Teacher pay is set locally, district by district, so it varies by geography more than almost any other profession. That makes the standard "highest paying states for teachers" table extra misleading: it ranks sticker salary and ignores what that salary buys. Adjust 48 US metros for cost of living and two stories pop out. California really does pay teachers the most, even after its prices. And a teacher effectively cannot buy a home in most of the metros that pay best, with exactly one escape hatch.
Full disclosure: I build kultranz.com, a salary and cost-of-living data site, and this study runs on data I maintain. Sources are named government series, the dataset is CC BY 4.0, and there is a free no-key API at the end so you can rerun every number in this post.
The method, in one line
real pay = average salary / cost-of-living index x 100. The index is BEA Regional Price Parity: 100 is the US average, 112 means prices run about 12 percent above it, so a dollar there buys roughly 89 cents of average-priced goods. Wages are BLS OEWS averages per metro, cost of living is BEA RPP, home values are Census ACS medians.
The 10 metros where teacher pay goes furthest
| Rank | Metro | Average salary | Cost index | Real pay | Home price / salary |
|---|---|---|---|---|---|
| 1 | San Diego, CA | $119,850 | 112 | $107,117 | 7.1x |
| 2 | Fresno, CA | $108,410 | 102 | $106,120 | 3.2x |
| 3 | San Jose, CA | $113,870 | 110 | $103,122 | 10.4x |
| 4 | San Francisco, CA (Oakland market) | $107,320 | 116 | $92,827 | 12.9x |
| 5 | Sacramento, CA | $98,700 | 107 | $92,528 | 4.9x |
| 6 | Los Angeles, CA (Long Beach market) | $104,840 | 114 | $92,316 | 8.4x |
| 7 | Portland, OR | $94,580 | 105 | $89,716 | 5.9x |
| 8 | New York, NY | $99,400 | 113 | $88,306 | 7.6x |
Eight of the top ten real-pay metros are Californian. But read the last column before you update your resume. San Francisco pays $107,320 nominally, drops to $92,827 after costs, and still asks 12.9 years of salary for a median home. San Jose asks 10.4x. The only big California metro where a teacher's real pay is near the top and a home is remotely reachable is Fresno: number 2 on real pay ($106,120, within $1,000 of San Diego) at 3.2x salary. Fresno is, by this math, the single best deal for a teacher in America.
Where a teacher salary vanishes
| Metro | Average salary | Cost index | Real pay | Home price / salary |
|---|---|---|---|---|
| New Orleans, LA | $58,730 | 93 | $63,425 | 5.0x |
| Fort Worth, TX | $64,851 | 103 | $62,907 | 4.3x |
| Nashville, TN | $60,600 | 96 | $62,904 | 6.3x |
| Charlotte, NC | $58,430 | 97 | $60,022 | 6.0x |
| Colorado Springs, CO | $58,400 | 101 | $57,990 | 7.2x |
| Tucson, AZ | $54,030 | 97 | $55,761 | 4.5x |
| Raleigh, NC | $54,680 | 98 | $55,707 | 6.9x |
| Miami, FL | $61,040 | 114 | $53,471 | 7.8x |
Miami is last again, and it is not close: $61,040 nominal collapses to $53,471 of real pay under a 114 cost index, with homes at 7.8x salary. It is the worst combination of low real pay and poor affordability on the whole board. New Orleans shows the mirror-image effect: a bottom-cluster nominal salary that lands on top of this table because its 93 index stretches every dollar.
I have run this adjustment for nurses and software developers too, and Miami ranks last every time. If a district recruiter quotes you a Miami salary with no cost context, that number is the least honest part of the conversation.
The tax layer
Cost of living is half the correction; state income tax is the other half. Florida levies no wage tax, which softens Miami slightly at the paycheck level, while California clips its own top metros. On the 2026 schedule engine, a $75k single filer nets about $61,600 in the nine no-wage-tax states versus the mid $56ks in California. California still wins on real pay after both layers, but by far less than district salary schedules imply.
Rerun it yourself, no key required
The same data backs a hosted API, free tier 25 requests a day, no signup:
curl "https://api.kultranz.com/salaries?job=teacher&city=Fresno" { "data": { "count": 1, "records": [ { "job_title": "Teacher", "city": "Fresno", "state": "CA", "avg_salary": 108410, "salary_median": 101980, "salary_75th": 139630, "salary_90th": 142690, "rpp_all_items": 102.158, "median_rent": 1324, "median_home_value": 348500 } ] } } That is a live response, trimmed for width. Notice the percentile spread: the 75th percentile in Fresno is $139,630, which is what "top of the salary schedule plus stipends" looks like in the data. The whole ranking is four lines of Python against /salaries:
import requests def real_pay(city): r = requests.get("https://api.kultranz.com/salaries", params={"job": "teacher", "city": city}, timeout=10).json() rec = r["data"]["records"][0] return rec["avg_salary"] / rec["rpp_all_items"] * 100 for city in ["San Diego", "Fresno", "San Francisco", "Miami"]: print(f"{city}: ${real_pay(city):,.0f}") Full endpoint list, including the take-home /paycheck calculator behind the tax layer, is on the API docs page. The interactive 48-metro version of this study is on the site.
The raw dataset
The metro cost-of-living side (BEA RPP plus median rent, home value, income, population for 50 metros) is open data, CC BY 4.0:
- GitHub: kultranz-cost-of-living-index
- Kaggle: us-metro-cost-of-living-index-2026
- Hugging Face: kultranz/us-metro-cost-of-living
And since teachers negotiate offers too, whether across districts or into a new state: the same engine generates a one-page Salary Negotiation Brief (your percentile, the local pay ladder, a counter-offer script, after-tax math) for $19 at kultranz.com/negotiation-brief.
Caveats, so nobody gets burned
These are occupation and metro averages from BLS OEWS; individual teacher pay moves with step schedules, graduate credits, stipends, and union contracts far more than most salaries. The index is regional and all-items, so a rent-heavy personal basket in an expensive metro diverges further than the average. Home ratio uses median values against average salary, a coarse affordability proxy. Nothing here is financial advice, and the full method is on the methodology page. If your metro's numbers look wrong, tell me: corrections land in the canonical data, and every consumer of the dataset and API picks them up on the next deploy.

