Skip to contents

Utah has one of the youngest populations in America and keeps adding students while most states shrink–but dig into the district-level data and the story gets complicated fast. Salt Lake City is hemorrhaging enrollment, charter schools serve nearly 1 in 4 students, and Hispanic enrollment has surged 46% in a decade.

Part of the state schooldata project, extending the original njschooldata package to all 50 states.

Full documentation – all 15 stories with interactive charts, getting-started guide, and complete function reference.

Highlights

library(utschooldata)
library(dplyr)
library(tidyr)
library(ggplot2)

theme_set(theme_minimal(base_size = 14))

# Get available years dynamically
available_years <- get_available_years()
min_year <- min(available_years)
max_year <- max(available_years)

enr <- fetch_enr_multi(available_years, use_cache = TRUE)

1. Salt Lake City district lost 17% of students since 2019

While suburban districts boom, Salt Lake City School District has declined from over 22,000 to under 19,000 students–a loss driven by housing costs and demographic shifts in the urban core.

salt_lake <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         district_name == "Salt Lake District") |>
  select(end_year, district_name, n_students) |>
  mutate(change = n_students - lag(n_students),
         pct_change = round(change / lag(n_students) * 100, 1))

salt_lake
#> # A tibble: 7 x 5
#>   end_year district_name      n_students change pct_change
#>      <dbl> <chr>                   <dbl>  <dbl>      <dbl>
#> 1     2019 Salt Lake District      22401     NA       NA
#> 2     2020 Salt Lake District      22017   -384       -1.7
#> 3     2021 Salt Lake District      20536  -1481       -6.7
#> 4     2022 Salt Lake District      19833   -703       -3.4
#> 5     2023 Salt Lake District      19449   -384       -1.9
#> 6     2024 Salt Lake District      18966   -483       -2.5
#> 7     2025 Salt Lake District      18535   -431       -2.3
Salt Lake decline
Salt Lake decline

(source)

2. Charter schools serve a growing share of Utah students

Utah has a robust charter school sector, with nearly 25% of public school students attending charter schools–one of the highest rates in the nation.

enr_latest <- fetch_enr(max_year, use_cache = TRUE)

state_total <- enr_latest |>
  filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  pull(n_students)

charter_total <- enr_latest |>
  filter(is_charter, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  summarize(charter_total = sum(n_students, na.rm = TRUE)) |>
  pull(charter_total)

charter_summary <- tibble(
  sector = c("All Public Schools", "Charter Schools"),
  enrollment = c(state_total, charter_total),
  pct = c(100, round(charter_total / state_total * 100, 1))
)

charter_summary
#> # A tibble: 2 x 3
#>   sector             enrollment   pct
#>   <chr>                   <dbl> <dbl>
#> 1 All Public Schools     667789 100
#> 2 Charter Schools        163710  24.5
Charters
Charters

(source)

3. Hispanic enrollment grew 46% since 2014

Utah’s Hispanic student population has grown significantly faster than overall enrollment, adding nearly 45,000 students in just over a decade.

hispanic <- enr |>
  filter(is_state, grade_level == "TOTAL", subgroup == "hispanic") |>
  select(end_year, n_students) |>
  mutate(change = n_students - lag(n_students),
         pct_change = round(change / lag(n_students) * 100, 1))

hispanic
#> # A tibble: 12 x 4
#>    end_year n_students change pct_change
#>       <dbl>      <dbl>  <dbl>      <dbl>
#>  1     2014      97388     NA       NA
#>  2     2015     101390   4002        4.1
#>  3     2016     104457   3067        3
#>  4     2017     108074   3617        3.5
#>  5     2018     110931   2857        2.6
#>  6     2019     113945   3014        2.7
#>  7     2020     117486   3541        3.1
#>  8     2021     119393   1907        1.6
#>  9     2022     126467   7074        5.9
#> 10     2023     131954   5487        4.3
#> 11     2024     132110    156        0.1
#> 12     2025     142267  10157        7.7
Hispanic growth
Hispanic growth

(source)

Data Taxonomy

Category Years Function Details
Enrollment 2014-2026 fetch_enr() / fetch_enr_multi() State, district, school. Race, gender, FRPL, SpEd, LEP
Assessments Not yet available
Graduation Not yet available
Directory Current fetch_directory() District, school. Principal, superintendent, address, phone
Per-Pupil Spending Not yet available
Accountability Not yet available
Chronic Absence Not yet available
EL Progress Not yet available
Special Ed Not yet available

See the full data category taxonomy

Quick Start

R

# install.packages("devtools")
devtools::install_github("almartin82/utschooldata")

library(utschooldata)
library(dplyr)

# Get 2025 enrollment data
enr <- fetch_enr(2025, use_cache = TRUE)

# View state totals
enr |>
  filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  select(end_year, n_students)
#> # A tibble: 1 x 2
#>   end_year n_students
#>      <dbl>      <dbl>
#> 1     2025     667789

Python

import pyutschooldata as ut

# Fetch 2025 data
enr = ut.fetch_enr(2025)

# Statewide total
total = enr[(enr['is_state']) &
            (enr['grade_level'] == 'TOTAL') &
            (enr['subgroup'] == 'total_enrollment')]['n_students'].sum()
print(f"{total:,} students")
# 667,789 students

# Check available years
years = ut.get_available_years()
print(f"Data available: {min(years)}-{max(years)}")
# Data available: 2014-2026

Explore More

Full analysis with 15 stories: - Enrollment trends – 15 stories - Function reference

Data Notes

Data Source

Data is downloaded from the Utah State Board of Education (USBE) Data and Statistics portal:

Years Available

Era Years Format Notes
Current 2014-2026 Excel (.xlsx) Fall Enrollment by Grade Level and Demographics

Earliest available year: 2014 Most recent available year: 2026 Total years of data: 13 years

Aggregation Levels

  • State: Total Utah enrollment
  • District (LEA): Local Education Agency totals (aggregated from schools)
  • Campus (School): Individual school enrollment

Demographics Available

Category Fields
Race/Ethnicity White, Black, Hispanic, Asian, Native American, Pacific Islander, Multiracial
Gender Male, Female
Special Populations Economically Disadvantaged, English Learners (ELL/LEP), Special Education
Grade Levels Pre-K, K, 1-12

Known Caveats

  1. Data Suppression: Small cell sizes may be suppressed for privacy (typically N < 10)
  2. Charter Schools: Charter schools are included and can be identified where the charter_flag column is available
  3. Historical Changes: District boundaries and school configurations may change year to year
  4. October 1 Count: All enrollment figures represent the official October 1 count date

Deeper Dive

4. Utah’s enrollment continues to grow

Utah has one of the youngest populations in the nation and continues to see steady enrollment growth, unlike many states that saw declines after COVID.

state_totals <- enr |>
  filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  select(end_year, n_students) |>
  mutate(change = n_students - lag(n_students),
         pct_change = round(change / lag(n_students) * 100, 2))

state_totals
#> # A tibble: 13 x 4
#>    end_year n_students change pct_change
#>       <dbl>      <dbl>  <dbl>      <dbl>
#>  1     2014     612088     NA      NA
#>  2     2015     621748   9660       1.58
#>  3     2016     633461  11713       1.88
#>  4     2017     644004  10543       1.66
#>  5     2018     651796   7792       1.21
#>  6     2019     658952   7156       1.1
#>  7     2020     666858   7906       1.2
#>  8     2021     665306  -1552      -0.23
#>  9     2022     674351   9045       1.36
#> 10     2023     674650    299       0.04
#> 11     2024     672662  -1988      -0.29
#> 12     2025     667789  -4873      -0.72
Statewide enrollment
Statewide enrollment

(source)

5. Granite and Alpine are Utah’s enrollment giants

Utah’s two largest districts–Granite and Alpine–each serve well over 57,000 students, but their trajectories differ. Salt Lake City has seen declines while suburban districts grow.

large_districts <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Granite|Alpine|Davis|Jordan|Canyons|Salt Lake City", district_name, ignore.case = TRUE)) |>
  select(end_year, district_name, n_students)

large_districts |>
  filter(end_year == max(end_year)) |>
  arrange(desc(n_students))
#> # A tibble: 6 x 3
#>   end_year district_name      n_students
#>      <dbl> <chr>                   <dbl>
#> 1     2025 Alpine District         84757
#> 2     2025 Davis District          69602
#> 3     2025 Jordan District         57083
#> 4     2025 Granite District        57038
#> 5     2025 Canyons District        32289
#> 6     2025 Salt Lake District      18535
Top districts
Top districts

(source)

6. Utah’s student body is diversifying

While Utah remains less diverse than national averages, Hispanic enrollment has grown substantially over the past decade, now representing 21% of students.

demographics <- enr_latest |>
  filter(is_state, grade_level == "TOTAL",
         subgroup %in% c("hispanic", "white", "black", "asian", "native_american", "pacific_islander", "multiracial")) |>
  mutate(pct = round(pct * 100, 1)) |>
  select(subgroup, n_students, pct) |>
  arrange(desc(n_students))

demographics
#> # A tibble: 7 x 3
#>   subgroup         n_students   pct
#>   <chr>                 <dbl> <dbl>
#> 1 white                463352  69.4
#> 2 hispanic             142267  21.3
#> 3 multiracial           25478   3.8
#> 4 asian                 11184   1.7
#> 5 pacific_islander      10844   1.6
#> 6 black                  8827   1.3
#> 7 native_american        5837   0.9
Demographics
Demographics

(source)

7. Pacific Islander students are a unique Utah story

Utah has one of the highest concentrations of Pacific Islander students in the nation, reflecting the state’s significant Polynesian community, particularly in Salt Lake County.

pi_districts <- enr_latest |>
  filter(is_district, grade_level == "TOTAL", subgroup == "pacific_islander") |>
  filter(n_students > 100) |>
  mutate(pct = round(pct * 100, 2)) |>
  select(district_name, n_students, pct) |>
  arrange(desc(pct)) |>
  head(10)

pi_districts
#> # A tibble: 10 x 3
#>    district_name                  n_students   pct
#>    <chr>                               <dbl> <dbl>
#>  1 Mana Academy Charter School           185 61.5
#>  2 Wallace Stegner Academy               143  6.6
#>  3 Salt Lake District                    919  4.96
#>  4 Granite District                     2092  3.67
#>  5 Provo District                        432  3.21
#>  6 Logan City District                   135  2.67
#>  7 Jordan District                      1272  2.23
#>  8 Tooele District                       349  2.23
#>  9 Alpine District                      1287  1.52
#> 10 Davis District                       1025  1.47
Pacific Islander
Pacific Islander

(source)

8. Utah County is the growth engine

Provo, Alpine, and Nebo districts in Utah County are seeing consistent growth as young families settle along the I-15 corridor south of Salt Lake.

utah_county <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Alpine|Provo|Nebo", district_name, ignore.case = TRUE)) |>
  group_by(district_name) |>
  arrange(end_year) |>
  summarize(
    first_year = first(n_students),
    last_year = last(n_students),
    pct_change = round((last_year / first_year - 1) * 100, 1),
    .groups = "drop"
  ) |>
  arrange(desc(pct_change))

stopifnot(nrow(utah_county) > 0)
utah_county
#> # A tibble: 3 x 4
#>   district_name   first_year last_year pct_change
#>   <chr>                <dbl>     <dbl>      <dbl>
#> 1 Nebo District        33117     42946       29.7
#> 2 Alpine District      79748     84757        6.3
#> 3 Provo District       16165     13463      -16.7
Growth chart
Growth chart

(source)

9. Rural districts face decline

While the Wasatch Front booms, rural districts in southern and eastern Utah face enrollment pressure as families move to urban centers for jobs and services.

rural <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Carbon|Emery|Grand|San Juan|Millard", district_name, ignore.case = TRUE)) |>
  group_by(district_name) |>
  filter(n() >= 5) |>
  arrange(end_year) |>
  summarize(
    first_year = first(n_students),
    last_year = last(n_students),
    pct_change = round((last_year / first_year - 1) * 100, 1),
    .groups = "drop"
  ) |>
  arrange(pct_change)

stopifnot(nrow(rural) > 0)
rural
#> # A tibble: 5 x 4
#>   district_name     first_year last_year pct_change
#>   <chr>                  <dbl>     <dbl>      <dbl>
#> 1 Grand District          1520      1371       -9.8
#> 2 Emery District          2181      1986       -8.9
#> 3 Carbon District         3484      3186       -8.6
#> 4 San Juan District       2876      2768       -3.8
#> 5 Millard District        2916      3064        5.1
Regional chart
Regional chart

(source)

10. Washington County is Utah’s fastest-growing region

The St. George area (Washington County School District) has exploded with growth as retirees and remote workers flock to southern Utah.

washington <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Washington", district_name, ignore.case = TRUE)) |>
  select(end_year, district_name, n_students) |>
  mutate(change = n_students - lag(n_students),
         pct_change = round(change / lag(n_students) * 100, 1))

washington
#> # A tibble: 14 x 5
#>    end_year district_name      n_students change pct_change
#>       <dbl> <chr>                   <dbl>  <dbl>      <dbl>
#>  1     2019 Washington District     31074     NA       NA
#>  2     2020 Washington District     33884   2810        9
#>  3     2021 Washington District     35346   1462        4.3
#>  4     2022 Washington District     36453   1107        3.1
#>  5     2023 Washington District     36623    170        0.5
#>  6     2024 Washington District     36753    130        0.4
#>  7     2025 Washington District     36006   -747       -2
Washington County
Washington County

(source)

11. Kindergarten enrollment dipped during COVID but recovered

Unlike many states, Utah saw kindergarten enrollment bounce back relatively quickly after COVID disruptions, though it has since declined further.

covid_grades <- enr |>
  filter(is_state, subgroup == "total_enrollment",
         grade_level %in% c("K", "01", "05", "09")) |>
  select(end_year, grade_level, n_students) |>
  pivot_wider(names_from = grade_level, values_from = n_students)

covid_grades
#> # A tibble: 12 x 5
#>    end_year     K   `01`   `05`   `09`
#>       <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#>  1     2014 50363  51424  48499  45721
#>  2     2015 48859  51431  49181  46699
#>  3     2016 48327  50322  49563  47616
#>  4     2017 48242  49981  51455  48522
#>  5     2018 47605  49812  53389  50125
#>  6     2019 49081  49081  53465  51044
#>  7     2020 48789  50699  52766  51908
#>  8     2021 46874  49242  51542  53340
#>  9     2022 48744  49624  51764  55245
#> 10     2023 46655  50346  50921  55330
#> 11     2024 45217  48138  52547  54351
#> 12     2025 44776  46313  51677  53658
COVID grades
COVID grades

(source)

12. High school enrollment is surging

As larger elementary cohorts from the 2010s move through the system, Utah high schools are seeing significant enrollment growth–up 25% since 2014.

hs_trend <- enr |>
  filter(is_state, subgroup == "total_enrollment",
         grade_level %in% c("09", "10", "11", "12")) |>
  group_by(end_year) |>
  summarize(hs_total = sum(n_students, na.rm = TRUE), .groups = "drop") |>
  mutate(change = hs_total - lag(hs_total),
         pct_change = round(change / lag(hs_total) * 100, 1))

hs_trend
#> # A tibble: 12 x 4
#>    end_year hs_total change pct_change
#>       <dbl>    <dbl>  <dbl>      <dbl>
#>  1     2014   173049     NA       NA
#>  2     2015   178071   5022        2.9
#>  3     2016   183492   5421        3
#>  4     2017   187727   4235        2.3
#>  5     2018   192340   4613        2.5
#>  6     2019   196008   3668        1.9
#>  7     2020   200437   4429        2.3
#>  8     2021   205808   5371        2.7
#>  9     2022   210817   5009        2.4
#> 10     2023   214148   3331        1.6
#> 11     2024   216094   1946        0.9
#> 12     2025   216526    432        0.2
High school
High school

(source)

13. English learner population nearly doubled

The number of English learners (ELL/LEP) in Utah schools has grown from 34,000 to over 61,000 since 2014–an 79% increase.

ell_trend <- enr |>
  filter(is_state, grade_level == "TOTAL", subgroup == "lep") |>
  select(end_year, n_students, pct) |>
  mutate(pct = round(pct * 100, 1),
         change = n_students - lag(n_students),
         pct_change = round(change / lag(n_students) * 100, 1))

ell_trend
#> # A tibble: 12 x 5
#>    end_year n_students   pct change pct_change
#>       <dbl>      <dbl> <dbl>  <dbl>      <dbl>
#>  1     2014      34394   5.6     NA       NA
#>  2     2015      37033   6       2639      7.7
#>  3     2016      38414   6.1     1381      3.7
#>  4     2017      39662   6.2     1248      3.2
#>  5     2018      43763   6.7     4101     10.3
#>  6     2019      49374   7.5     5611     12.8
#>  7     2020      53234   8       3860      7.8
#>  8     2021      52788   7.9     -446     -0.8
#>  9     2022      55546   8.2     2758      5.2
#> 10     2023      59176   8.8     3630      6.5
#> 11     2024      59147   8.8      -29      0
#> 12     2025      61481   9.2     2334      3.9
ELL growth
ELL growth

(source)

14. Nearly 1 in 3 students are economically disadvantaged

About 29% of Utah students qualify as economically disadvantaged–lower than the national average but still representing nearly 194,000 students.

special_pops <- enr_latest |>
  filter(is_state, grade_level == "TOTAL",
         subgroup %in% c("econ_disadv", "lep", "special_ed")) |>
  mutate(pct = round(pct * 100, 1)) |>
  select(subgroup, n_students, pct) |>
  arrange(desc(n_students))

special_pops
#> # A tibble: 3 x 3
#>   subgroup    n_students   pct
#>   <chr>            <dbl> <dbl>
#> 1 econ_disadv     193572  29
#> 2 special_ed       88462  13.2
#> 3 lep              61481   9.2
Special populations
Special populations

(source)

15. Elementary enrollment is declining while high school grows

Utah kindergarten enrollment dropped 11% since its 2014 peak, even as high school grades are at record levels. This points to future enrollment declines.

grades <- enr_latest |>
  filter(is_state, subgroup == "total_enrollment") |>
  filter(!grade_level %in% c("TOTAL")) |>
  select(grade_level, n_students) |>
  arrange(desc(n_students))

grades
#> # A tibble: 14 x 2
#>    grade_level n_students
#>    <chr>            <dbl>
#>  1 11               54834
#>  2 10               54609
#>  3 09               53658
#>  4 12               53425
#>  5 08               53017
#>  6 06               52775
#>  7 07               51808
#>  8 05               51677
#>  9 04               51285
#> 10 03               51101
#> 11 02               48511
#> 12 01               46313
#> 13 K                44776
#> 14 PK               16008
Grade distribution
Grade distribution

(source)