Fetch and analyze Florida school enrollment, assessment, and graduation data from the Florida Department of Education (FLDOE) in R or Python. Nearly 3 million students across 67 county districts in the Sunshine State – 18 years of enrollment (2008-2025), assessments (2019-2025), and graduation rates (2016-2024).
Part of the njschooldata family.
Full documentation – all 30 stories with interactive charts, getting-started guide, and complete function reference.
Highlights
library(flschooldata)
library(dplyr)
library(tidyr)
library(ggplot2)
theme_set(theme_minimal(base_size = 14))
enr <- fetch_enr_multi(2015:2024, use_cache = TRUE)
enr_2024 <- fetch_enr(2024, use_cache = TRUE)1. Hispanic enrollment surpassed White for the first time
A demographic milestone: Hispanic student enrollment has overtaken White enrollment in Florida, reflecting broader population shifts.
crossover <- enr |>
filter(is_state, grade_level == "TOTAL",
subgroup %in% c("hispanic", "white")) |>
select(end_year, subgroup, n_students) |>
pivot_wider(names_from = subgroup, values_from = n_students)
crossover
stopifnot(nrow(crossover) > 0)
#> end_year white hispanic
#> 1 2015 1108227 846425
#> 2 2016 1101823 879982
#> 3 2017 1089439 912300
#> 4 2018 1077811 937352
#> 5 2019 1063838 963338
#> 6 2020 1054580 986005
#> 7 2021 1016772 974588
#> 8 2022 1021630 1003659
#> 9 2023 1014065 1043390
#> 10 2024 988822 1066935
2. Just over half of Florida third graders read on grade level
In 2024, 55% of Florida 3rd graders scored at Level 3 or above on the FAST ELA Reading assessment.
assess_2024 <- fetch_assessment(2024, "ela", grade = 3, level = "district",
tidy = FALSE, use_cache = TRUE)
state_g3 <- assess_2024 |>
filter(is_state) |>
select(end_year, subject, grade, n_tested, pct_proficient,
pct_level_1, pct_level_2, pct_level_3, pct_level_4, pct_level_5)
state_g3
stopifnot(nrow(state_g3) > 0)
#> end_year subject grade n_tested pct_proficient pct_level_1 pct_level_2
#> 1 2024 ELA 03 216473 55 22 22
#> pct_level_3 pct_level_4 pct_level_5
#> 1 23 19 13
3. Multiracial students are the fastest-growing demographic
While Hispanic students are the largest group, multiracial student enrollment has grown at the highest rate percentage-wise since 2015 (34.9% growth, compared to 26.1% for Hispanic students and 15.3% for Asian students).
demo_trend <- enr |>
filter(is_state, grade_level == "TOTAL",
subgroup %in% c("hispanic", "white", "black", "asian", "multiracial")) |>
select(end_year, subgroup, n_students) |>
group_by(subgroup) |>
mutate(pct_change = round((n_students / first(n_students) - 1) * 100, 1)) |>
ungroup()
demo_2024 <- demo_trend |>
filter(end_year == 2024) |>
arrange(desc(pct_change))
demo_2024
stopifnot(nrow(demo_2024) > 0)
#> end_year subgroup n_students pct_change
#> 1 2024 multiracial 119907 34.9
#> 2 2024 hispanic 1066935 26.1
#> 3 2024 asian 81688 15.3
#> 4 2024 black 599867 -4.2
#> 5 2024 white 988822 -10.8
Data Taxonomy
| Category | Years | Function | Details |
|---|---|---|---|
| Enrollment | 2008-2025 |
fetch_enr() / fetch_enr_multi()
|
State, district, school. Race, gender |
| Assessments | 2019, 2022-2025 |
fetch_assessment() / fetch_assessment_multi()
|
ELA grades 3-10, Math grades 3-8. District, school |
| Graduation | 2016-2024 | fetch_graduation() |
State, district, school. 4-year cohort rates |
| Directory | Current | fetch_directory() |
All schools. Principal, address, phone, charter status, geo-coordinates |
| 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 for what each category covers.
Quick Start
R
# install.packages("remotes")
remotes::install_github("almartin82/flschooldata")
library(flschooldata)
library(dplyr)
# === Enrollment Data ===
# Fetch one year
enr_2025 <- fetch_enr(2025)
# Fetch multiple years
enr_multi <- fetch_enr_multi(2020:2025)
# State totals
enr_2025 %>%
filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL")
# District breakdown
enr_2025 %>%
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") %>%
arrange(desc(n_students))
# Miami-Dade County (district 13)
enr_2025 %>%
filter(district_id == "13", subgroup == "total_enrollment")
# === Assessment Data ===
# Fetch 2024 ELA Grade 3 district data
assess_2024 <- fetch_assessment(2024, "ela", grade = 3)
# Fetch all grades
assess_all_grades <- fetch_assessment(2024, "ela")
# Fetch Math data
math_2024 <- fetch_assessment(2024, "math")
# State proficiency
assess_2024 %>%
filter(is_state) %>%
select(subject, grade, pct_proficient)
# Check available years
get_available_assessment_years()Python
import pyflschooldata as fl
# === Enrollment Data ===
# Check available years
years = fl.get_available_years()
print(f"Data available: {years['min_year']}-{years['max_year']}")
# Fetch one year
df = fl.fetch_enr(2025)
# Fetch multiple years
df_multi = fl.fetch_enr_multi([2020, 2021, 2022, 2023, 2024, 2025])
# State totals
state_total = df[(df['is_state'] == True) &
(df['subgroup'] == 'total_enrollment') &
(df['grade_level'] == 'TOTAL')]
# District breakdown
districts = df[(df['is_district'] == True) &
(df['subgroup'] == 'total_enrollment') &
(df['grade_level'] == 'TOTAL')].sort_values('n_students', ascending=False)
# === Assessment Data ===
# Fetch 2024 ELA Grade 3 data
assess = fl.fetch_assessment(2024, subject='ela', grade=3)
# State proficiency
state_assess = assess[assess['is_state'] == True]
print(state_assess[['subject', 'grade', 'pct_proficient']])
# Check available assessment years
assess_years = fl.get_available_assessment_years()
print(f"Assessment data: {assess_years['years']}")Explore More
Full analysis with 30 stories across 2 vignettes:
- Enrollment trends – 15 stories
- Assessment analysis – 15 stories
- Function reference
Data Notes
Source: Florida Department of Education – PK-12 Data Publications
Enrollment Data:
| Years | Source | Notes |
|---|---|---|
| 2014-2025 | FLDOE Membership Files | Full school-level demographic data |
| 2008-2013 | FLDOE FTE Files | District-level totals only |
Assessment Data:
| Years | Assessment | Notes |
|---|---|---|
| 2023-2025 | FAST (Florida Assessment of Student Thinking) | ELA Grades 3-10, Math Grades 3-8 |
| 2019, 2022 | FSA (Florida Standards Assessments) | No 2020/2021 due to COVID-19 |
Graduation Data: 2016-2024, 4-year cohort graduation rates at state, district, and school levels.
What’s included:
- Levels: State, district (67 county + special), school (~4,500)
- Demographics: White, Black, Hispanic, Asian, American Indian, Pacific Islander, Two or More Races
- Gender: Male, Female
- Grade levels: Pre-K through 12
Florida ID system:
- 67 county districts: Codes 01-67 (one per county)
- Special districts: Codes 71-75 (lab schools, FL School for Deaf/Blind)
- School numbers: 4-digit codes
-
Combined ID:
DD-SSSSformat (e.g., “13-0021” for a Miami-Dade school)
Caveats:
- Pre-2014 data has limited demographics (FTE files only)
- Charter school identification not directly available in membership files
- ESE, ELL, and free/reduced lunch in separate files (not yet integrated)
- Assessment results may be suppressed for small n-sizes to protect student privacy
Deeper Dive
4. Florida is America’s fourth-largest school system
Florida public schools serve nearly 3 million students, trailing only California, Texas, and New York.
enr <- fetch_enr_multi(2015:2024, use_cache = TRUE)
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
stopifnot(nrow(state_totals) > 0)
#> end_year n_students change pct_change
#> 1 2015 2750108 NA NA
#> 2 2016 2785286 35178 1.28
#> 3 2017 2810249 24963 0.90
#> 4 2018 2826290 16041 0.57
#> 5 2019 2840029 13739 0.49
#> 6 2020 2852303 12274 0.43
#> 7 2021 2784931 -67372 -2.36
#> 8 2022 2826573 41642 1.50
#> 9 2023 2864292 37719 1.33
#> 10 2024 2865908 1616 0.06
5. Miami-Dade is larger than most states
Miami-Dade County Public Schools, with 340,000+ students, is the fourth-largest school district in America.
enr_2024 <- fetch_enr(2024, use_cache = TRUE)
top_10 <- enr_2024 |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
arrange(desc(n_students)) |>
head(10) |>
select(district_name, n_students)
top_10
stopifnot(nrow(top_10) > 0)
#> district_name n_students
#> 1 MIAMI-DADE 337610
#> 2 BROWARD 251397
#> 3 HILLSBOROUGH 224144
#> 4 ORANGE 207695
#> 5 PALM BEACH 191390
#> 6 DUVAL 129083
#> 7 POLK 115990
#> 8 LEE 99952
#> 9 PINELLAS 90969
#> 10 PASCO 85808
6. COVID barely dented Florida enrollment
While other states saw sharp declines, Florida’s enrollment dipped only briefly in 2021 and has since rebounded.
covid <- enr |>
filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL",
end_year >= 2019) |>
select(end_year, n_students) |>
mutate(change = n_students - lag(n_students))
covid
stopifnot(nrow(covid) > 0)
#> end_year n_students change
#> 1 2019 2840029 NA
#> 2 2020 2852303 12274
#> 3 2021 2784931 -67372
#> 4 2022 2826573 41642
#> 5 2023 2864292 37719
#> 6 2024 2865908 16167. Hispanic students are the plurality
Hispanic students now comprise over 35% of Florida enrollment, surpassing white students.
demographics <- enr_2024 |>
filter(is_state, grade_level == "TOTAL",
subgroup %in% c("hispanic", "white", "black", "asian", "multiracial")) |>
mutate(pct = round(pct * 100, 1)) |>
select(subgroup, n_students, pct) |>
arrange(desc(n_students))
demographics
stopifnot(nrow(demographics) > 0)
#> subgroup n_students pct
#> 1 hispanic 1066935 37.2
#> 2 white 988822 34.5
#> 3 black 599867 20.9
#> 4 multiracial 119907 4.2
#> 5 asian 81688 2.9
8. Central Florida is the growth engine
Orange, Osceola, and Polk counties have been among the fastest-growing, driven by the Orlando metro boom.
central_fl <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Orange|Osceola|Polk", district_name, ignore.case = TRUE),
end_year %in% c(2015, 2024)) |>
group_by(district_name) |>
summarize(
y2015 = n_students[end_year == 2015],
y2024 = n_students[end_year == 2024],
pct_change = round((y2024 / y2015 - 1) * 100, 1),
.groups = "drop"
) |>
arrange(desc(pct_change))
central_fl
stopifnot(nrow(central_fl) > 0)
#> # A tibble: 3 x 4
#> district_name y2015 y2024 pct_change
#> <chr> <dbl> <dbl> <dbl>
#> 1 OSCEOLA 59276 74278 25.3
#> 2 POLK 99650 115990 16.4
#> 3 ORANGE 191640 207695 8.49. Broward and Miami-Dade are declining
South Florida’s two largest districts have been losing students as families relocate.
south_fl <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Broward|Miami-Dade", district_name, ignore.case = TRUE),
end_year >= 2018) |>
select(end_year, district_name, n_students) |>
pivot_wider(names_from = district_name, values_from = n_students)
south_fl
stopifnot(nrow(south_fl) > 0)
#> end_year BROWARD MIAMI-DADE
#> 1 2018 271951 354767
#> 2 2019 270961 350372
#> 3 2020 269163 347239
#> 4 2021 260224 334858
#> 5 2022 256027 329483
#> 6 2023 254728 335831
#> 7 2024 251397 337610
10. Florida Virtual School is a district unto itself
Florida Virtual School (FLVS) serves tens of thousands of students statewide.
virtual <- enr_2024 |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Virtual|FLVS", district_name, ignore.case = TRUE)) |>
select(district_name, n_students)
virtual
stopifnot(nrow(virtual) > 0)
#> district_name n_students
#> 1 FL VIRTUAL 887411. Kindergarten is the leading indicator
Florida kindergarten enrollment has been relatively stable, unlike states with sharp K declines.
k_trend <- enr |>
filter(is_state, subgroup == "total_enrollment",
grade_level %in% c("K", "01", "05", "09"),
end_year >= 2019) |>
select(end_year, grade_level, n_students) |>
pivot_wider(names_from = grade_level, values_from = n_students)
k_trend
stopifnot(nrow(k_trend) > 0)
#> end_year K 01 05 09
#> 1 2019 200437 206545 222947 221023
#> 2 2020 202460 207143 217518 223805
#> 3 2021 186147 200215 207750 227753
#> 4 2022 199099 200741 217770 231499
#> 5 2023 197925 209516 209060 237920
#> 6 2024 195032 204402 205135 23250612. Black students are 21% of enrollment
Florida has a significant Black student population, concentrated in South Florida and the Jacksonville region.
black_enr <- enr_2024 |>
filter(is_state, grade_level == "TOTAL", subgroup == "black") |>
select(subgroup, n_students, pct)
black_enr
stopifnot(nrow(black_enr) > 0)
#> subgroup n_students pct
#> 1 black 599867 0.209311313. Florida’s county-based system is unique
Florida organizes schools by county, with 67 county districts (plus a few specialty districts). This structure differs from most states.
county_count <- enr_2024 |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
summarize(
n_districts = n_distinct(district_name),
total_students = sum(n_students, na.rm = TRUE)
)
county_count
stopifnot(nrow(county_count) > 0)
#> n_districts total_students
#> 1 76 286590814. Tampa Bay is catching up to South Florida
Hillsborough and Pinellas counties represent Florida’s other major metro area. While South Florida declines, Tampa Bay has held steady.
tampa <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Hillsborough|Pinellas|Pasco", district_name, ignore.case = TRUE)) |>
group_by(district_name) |>
summarize(
y2015 = n_students[end_year == 2015],
y2024 = n_students[end_year == 2024],
pct_change = round((y2024 / y2015 - 1) * 100, 1),
.groups = "drop"
) |>
arrange(desc(y2024))
tampa
stopifnot(nrow(tampa) > 0)
#> # A tibble: 3 x 4
#> district_name y2015 y2024 pct_change
#> <chr> <dbl> <dbl> <dbl>
#> 1 HILLSBOROUGH 207457 224144 8
#> 2 PINELLAS 103754 90969 -12.3
#> 3 PASCO 69218 85808 24
15. Jacksonville is Florida’s hidden giant
Duval County (Jacksonville) often flies under the radar, but it’s Florida’s 6th largest district with over 125,000 students.
jax <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Duval", district_name, ignore.case = TRUE)) |>
select(end_year, district_name, n_students) |>
mutate(change = n_students - lag(n_students))
jax
stopifnot(nrow(jax) > 0)
#> end_year district_name n_students change
#> 1 2015 DUVAL 128665 NA
#> 2 2016 DUVAL 129169 504
#> 3 2017 DUVAL 129414 245
#> 4 2018 DUVAL 129562 148
#> 5 2019 DUVAL 130224 662
#> 6 2020 DUVAL 130283 59
#> 7 2021 DUVAL 126802 -3481
#> 8 2022 DUVAL 128939 2137
#> 9 2023 DUVAL 129788 849
#> 10 2024 DUVAL 129083 -705
16. Small rural counties face steep declines
While large metros grow, many of Florida’s smallest counties are losing students rapidly.
# Get the first and last year for comparison
first_year <- min(enr$end_year)
last_year <- max(enr$end_year)
county_change <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
end_year %in% c(first_year, last_year)) |>
group_by(district_name) |>
filter(n() == 2) |> # Only counties with both years
summarize(
y_first = n_students[end_year == first_year],
y_last = n_students[end_year == last_year],
change = y_last - y_first,
pct_change = round((y_last / y_first - 1) * 100, 1),
.groups = "drop"
)
# Counties losing the most (by %)
declining <- county_change |>
filter(y_first > 1000) |> # Exclude tiny counties
arrange(pct_change) |>
head(10)
declining
stopifnot(nrow(declining) > 0)
#> district_name y_first y_last change pct_change
#> 1 GADSDEN 5837 4598 -1239 -21.2
#> 2 LIBERTY 1330 1156 -174 -13.1
#> 3 PINELLAS 103754 90969 -12785 -12.3
#> 4 LAFAYETTE 1132 1007 -125 -11.0
#> 5 MADISON 2498 2228 -270 -10.8
#> 6 JACKSON 6726 6037 -689 -10.2
#> 7 DESOTO 4658 4199 -459 -9.9
#> 8 HARDEE 5095 4598 -497 -9.8
#> 9 TAYLOR 2885 2602 -283 -9.8
#> 10 CALHOUN 2149 1942 -207 -9.6
17. Miami-Dade outperforms the state average
Despite being the largest district with over 25,000 3rd graders tested, Miami-Dade’s 56% proficiency rate exceeds the state average.
large_districts <- assess_2024 |>
filter(!is_state, n_tested > 5000) |>
arrange(desc(n_tested)) |>
select(district_name, n_tested, pct_proficient) |>
head(10)
large_districts
stopifnot(nrow(large_districts) > 0)
#> district_name n_tested pct_proficient
#> 1 MIAMI-DADE 25178 56
#> 2 BROWARD 18457 57
#> 3 HILLSBOROUGH 16802 51
#> 4 ORANGE 15743 57
#> 5 PALM BEACH 14593 54
#> 6 DUVAL 10095 49
#> 7 POLK 9295 49
#> 8 LEE 7644 48
#> 9 PINELLAS 6654 62
#> 10 PASCO 6511 53