Code
library (DBI)
library (RPostgres)
library (flextable)
library (sf)
library (tidyverse)
# Ensure that the Quarto render and RStudio read the same environment vars
readRenviron (".Renviron" )
con <- dbConnect (
RPostgres:: Postgres (),
dbname = Sys.getenv ("PG_DBNAME" ),
host = Sys.getenv ("PG_HOST" ),
port = Sys.getenv ("PG_PORT" ),
user = Sys.getenv ("PG_USER" ),
password = Sys.getenv ("PG_PASSWORD" )
)
The following analyses were performed in support of Right to Counsel’s annual State of Evictions fact sheet.
Cumulative Eviction Filings
Number of eviction filings from January 1, 2020 - December 31, 2025
Code
SELECT
COUNT (DISTINCT indexnumberid)::integer
FROM oca_index
WHERE fileddate >= MAKE_DATE(2020 ,1 ,1 )
AND fileddate <= MAKE_DATE(2025 ,12 ,31 )
AND classification IN ('Holdover' , 'Non-Payment' )
AND (propertytype = 'Residential' OR propertytype IS NULL );
In New York State, there were 849,449 eviction-oriented (holdover and non-payment) filings from January 1, 2020 to December 31, 2025.
Please note that this analysis excludes commercial evictions within New York City. Unfortunately, outside of NYC, excluding commercial from residential eviction filings and executions is not possible given the current data.
Annual eviction filings
Code
SELECT
EXTRACT (YEAR FROM fileddate) AS filed_year,
COUNT (DISTINCT indexnumberid)::integer
FROM oca_index
WHERE fileddate >= MAKE_DATE(2020 ,1 ,1 )
AND fileddate <= MAKE_DATE(2025 ,12 ,31 )
AND classification IN ('Holdover' , 'Non-Payment' )
AND (propertytype = 'Residential' OR propertytype IS NULL )
GROUP BY filed_year;
The number of eviction-related (holdover and non-payment) eviction filings per year is:
Code
eviction_count_annual_table <- eviction_count_annual_df |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
set_header_labels (
filed_year = "Year" ,
count = "Eviction Filings"
) |>
colformat_num (j= 1 ,
big.mark = "" ) |>
align (j= 1 ,
align = "left" ,
part = "all" )
eviction_count_annual_table
Year
Eviction Filings
2020
100,546
2021
60,491
2022
165,470
2023
187,034
2024
171,311
2025
164,597
Which areas are hardest hit?
By court, January 1, 2020 - December 31, 2025:
Code
SELECT
court,
COUNT (DISTINCT indexnumberid)::integer
FROM oca_index
WHERE fileddate >= MAKE_DATE(2020 ,1 ,1 )
AND fileddate <= MAKE_DATE(2025 ,12 ,31 )
AND classification IN ('Holdover' , 'Non-Payment' )
AND (propertytype = 'Residential' OR propertytype IS NULL )
GROUP BY court
ORDER BY count DESC
LIMIT 10 ;
Code
eviction_count_courts_table <- eviction_count_courts_df |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
set_header_labels (
court = "Court" ,
count = "Eviction Filings"
)
eviction_count_courts_table
Court
Eviction Filings
Bronx County Civil Court
213,610
Kings County Civil Court
158,862
New York County Civil Court
100,066
Queens County Civil Court
97,647
Buffalo City Court
37,842
Rochester City Court
27,383
Nassau County District Court - 1st District
19,373
Yonkers City Court
17,666
Suffolk County District Court - 6th District
14,801
Syracuse City Court
14,481
By court, January 1, 2025 - December 31, 2025:
Code
SELECT
court,
COUNT (DISTINCT indexnumberid)::integer
FROM oca_index
WHERE fileddate >= MAKE_DATE(2025 ,1 ,1 )
AND fileddate <= MAKE_DATE(2025 ,12 ,31 )
AND classification IN ('Holdover' , 'Non-Payment' )
AND (propertytype = 'Residential' OR propertytype IS NULL )
GROUP BY court
ORDER BY count DESC
LIMIT 10 ;
Code
eviction_count_courts_25_table <- eviction_count_courts_25_df |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
set_header_labels (
court = "Court" ,
count = "Eviction Filings"
)
eviction_count_courts_25_table
Court
Eviction Filings
Bronx County Civil Court
40,462
Kings County Civil Court
31,167
New York County Civil Court
19,480
Queens County Civil Court
18,691
Buffalo City Court
7,597
Rochester City Court
5,566
Nassau County District Court - 1st District
3,432
Yonkers City Court
3,419
Suffolk County District Court - 6th District
2,803
Richmond County Civil Court
2,798
By NYS Assembly District: January 1, 2020 - December 31, 2025
Code
oca_index_5year_geom <- st_read (con, query = "
SELECT DISTINCT(i.indexnumberid),
ST_Transform(a.geom, 2263) AS geom
FROM oca_index i
JOIN oca_addresses a ON i.indexnumberid = a.indexnumberid
WHERE i.fileddate >= MAKE_DATE(2020,1,1)
AND i.fileddate <= MAKE_DATE(2025,12,31)
AND i.classification IN ('Holdover', 'Non-Payment')
AND (i.propertytype = 'Residential' OR i.propertytype IS NULL)
AND a.geom IS NOT NULL" )
In the following filing counts by area, note that only 827,239 eviction filings (97.39%) have a location
Code
bb <- read_sf ("https://services5.arcgis.com/GfwWNkhOj9bNBqoJ/arcgis/rest/services/NYC_Borough_Boundary/FeatureServer/0/query?where=1=1&outFields=*&outSR=4326&f=pgeojson" ) |>
st_transform (2263 ) |>
st_make_valid () |>
st_union ()
nysad <- read_sf ("https://services6.arcgis.com/EbVsqZ18sv1kVJ3k/ArcGIS/rest/services/NYS_Assembly_Districts/FeatureServer/0/query?where=0%3D0&outFields=*&f=geojson" ) |>
st_transform (2263 )
nyss <- read_sf ("https://services6.arcgis.com/EbVsqZ18sv1kVJ3k/ArcGIS/rest/services/NYS_Senate_Districts/FeatureServer/0/query?where=0%3D0&outFields=*&f=geojson" ) |>
st_transform (2263 )
nysad_downstate <- st_filter (nysad, bb, .predicate = st_intersects)
nysad_upstate <- st_filter (nysad, bb, .predicate = st_disjoint)
nyss_downstate <- st_filter (nyss, bb, .predicate = st_intersects)
nyss_upstate <- st_filter (nyss, bb, .predicate = st_disjoint)
Upstate Assembly Districts (Not intersecting with NYC Borough boundaries)
Code
nysad_upstate_5year <- oca_index_5year_geom |>
st_join (nysad_upstate |>
select (District),
left = FALSE ) |>
st_drop_geometry () |>
group_by (District) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nysad_upstate_5year_table <- nysad_upstate_5year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" )
nysad_upstate_5year_table
District
Eviction Filings
137
16,191
141
14,663
109
12,172
108
11,169
129
8,523
90
7,688
111
7,469
149
7,308
119
7,269
104
7,097
Downstate Assembly Districts (Intersecting with NYC Borough boundaries)
Code
nysad_downstate_5year <- oca_index_5year_geom |>
st_join (nysad_downstate |>
select (District),
left = FALSE ) |>
st_drop_geometry () |>
group_by (District) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nysad_downstate_5year_table <- nysad_downstate_5year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" )
nysad_downstate_5year_table
District
Eviction Filings
86
30,156
77
29,285
78
25,627
84
24,290
79
22,698
70
19,673
72
18,520
71
17,216
43
16,938
85
16,896
By NYS Assembly District: January 1, 2025 - December 31, 2025
Code
oca_index_1year_geom <- st_read (con, query = "
SELECT DISTINCT(i.indexnumberid),
ST_Transform(a.geom, 2263) AS geom
FROM oca_index i
JOIN oca_addresses a ON i.indexnumberid = a.indexnumberid
WHERE i.fileddate >= MAKE_DATE(2025,1,1)
AND i.fileddate <= MAKE_DATE(2025,12,31)
AND i.classification IN ('Holdover', 'Non-Payment')
AND (i.propertytype = 'Residential' OR i.propertytype IS NULL)
AND a.geom IS NOT NULL" )
Upstate Assembly Districts (Not intersecting with NYC Borough boundaries)
Code
nysad_upstate_1year <- oca_index_1year_geom |>
st_join (nysad_upstate |>
select (District),
left = FALSE ) |>
st_drop_geometry () |>
group_by (District) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nysad_upstate_1year_table <- nysad_upstate_1year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" )
nysad_upstate_1year_table
District
Eviction Filings
137
3,257
141
2,733
109
2,314
108
2,276
129
1,662
119
1,502
111
1,478
149
1,455
90
1,424
104
1,216
Downstate Assembly Districts (Intersecting with NYC Borough boundaries)
Code
nysad_downstate_1year <- oca_index_1year_geom |>
st_join (nysad_downstate |>
select (District),
left = FALSE ) |>
st_drop_geometry () |>
group_by (District) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nysad_downstate_1year_table <- nysad_downstate_1year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" )
nysad_downstate_1year_table
District
Eviction Filings
77
5,540
86
5,498
78
4,796
84
4,732
79
4,052
70
3,972
72
3,680
60
3,492
71
3,287
55
3,282
By NYS Senate District, January 1, 2020 - December 31, 2025
Upstate Senate Districts (Not intersecting with NYC Borough boundaries)
Code
nyss_upstate_5year <- oca_index_5year_geom |>
st_join (nyss_upstate |>
select (DISTRICT),
left = FALSE ) |>
st_drop_geometry () |>
group_by (DISTRICT) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nyss_upstate_5year_table <- nyss_upstate_5year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" ) |>
set_header_labels (
DISTRICT = "District"
)
nyss_upstate_5year_table
District
Eviction Filings
63
25,129
48
15,389
56
15,288
46
13,440
3
11,848
43
11,252
55
10,726
61
10,032
6
9,358
44
8,900
Downstate Senate Districts (Intersecting with NYC Borough boundaries)
Code
nyss_downstate_5year <- oca_index_5year_geom |>
st_join (nyss_downstate |>
select (DISTRICT),
left = FALSE ) |>
st_drop_geometry () |>
group_by (DISTRICT) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nyss_downstate_5year_table <- nyss_downstate_5year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" ) |>
set_header_labels (
DISTRICT = "District"
)
nyss_downstate_5year_table
District
Eviction Filings
32
59,743
33
52,048
31
47,214
29
43,663
30
38,461
20
30,843
19
30,346
36
28,840
34
24,362
21
24,203
By NYS Senate District, January 1, 2025 - December 31, 2025
Upstate Senate Districts (Not intersecting with NYC Borough boundaries)
Code
nyss_upstate_1year <- oca_index_1year_geom |>
st_join (nyss_upstate |>
select (DISTRICT),
left = FALSE ) |>
st_drop_geometry () |>
group_by (DISTRICT) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nyss_upstate_1year_table <- nyss_upstate_1year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" ) |>
set_header_labels (
DISTRICT = "District"
)
nyss_upstate_1year_table
District
Eviction Filings
63
4,732
56
3,059
48
2,959
46
2,600
43
2,289
55
2,216
3
2,198
61
2,081
44
1,749
6
1,639
Downstate Senate Districts (Intersecting with NYC Borough boundaries)
Code
nyss_downstate_1year <- oca_index_1year_geom |>
st_join (nyss_downstate |>
select (DISTRICT),
left = FALSE ) |>
st_drop_geometry () |>
group_by (DISTRICT) |>
summarize (` Eviction Filings ` = n ()) |>
arrange (desc (` Eviction Filings ` )) |>
head (10 )
nyss_downstate_1year_table <- nyss_downstate_1year |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" ) |>
set_header_labels (
DISTRICT = "District"
)
nyss_downstate_1year_table
District
Eviction Filings
32
10,743
33
9,563
31
9,093
29
8,683
30
7,613
19
6,161
36
5,837
20
5,554
34
4,877
25
4,775
Executed Evictions in 2025
Code
SELECT
DISTINCT i.indexnumberid,
w.executiondate
FROM oca_index i
JOIN oca_warrants w ON i.indexnumberid = w.indexnumberid
WHERE w.executiondate >= MAKE_DATE(2025 ,1 ,1 )
AND w.executiondate <= MAKE_DATE(2025 ,12 ,31 )
AND i.classification IN ('Holdover' , 'Non-Payment' )
AND (i.propertytype = 'Residential' OR i.propertytype IS NULL )
AND w.executiondate IS NOT NULL
Code
executed_evictions_25_geom <- st_read (con, query = "
WITH executed_evictions_25 AS (
SELECT
DISTINCT i.indexnumberid,
w.executiondate
FROM oca_index i
JOIN oca_warrants w ON i.indexnumberid = w.indexnumberid
WHERE w.executiondate >= MAKE_DATE(2025,1,1)
AND w.executiondate <= MAKE_DATE(2025,12,31)
AND i.classification IN ('Holdover', 'Non-Payment')
AND (i.propertytype = 'Residential' OR i.propertytype IS NULL)
AND w.executiondate IS NOT NULL
)
SELECT e.*,
ST_TRANSFORM(a.geom, 2263)
FROM executed_evictions_25 e
JOIN oca_addresses a on e.indexnumberid = a.indexnumberid
WHERE a.geom IS NOT NULL;" )
Note: Of the 14,187 evictions executed statewide in 2025, only 13,993 have a location associated with them (98.63%)
Code
nys_counties <- read_sf ("https://services6.arcgis.com/EbVsqZ18sv1kVJ3k/ArcGIS/rest/services/NYS_Civil_Boundaries/FeatureServer/2/query?where=0%3D0&outFields=*&f=geojson" ) |>
st_transform (2263 )
executed_evictions_25_byCty <- executed_evictions_25_geom |>
st_join (nys_counties |>
select (NAME)) |>
st_drop_geometry () |>
group_by (NAME) |>
summarize (` Executed Evictions ` = n ()) |>
arrange (desc (` Executed Evictions ` )) |>
head (10 )
executed_evictions_25_byCty_table <- executed_evictions_25_byCty |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
align (j= 1 ,
align = "left" ,
part = "all" ) |>
set_header_labels (
NAME = "County"
)
executed_evictions_25_byCty_table
County
Executed Evictions
Bronx
4,636
Kings
3,621
New York
2,063
Queens
1,991
Richmond
516
Schenectady
507
Niagara
126
Orange
117
Montgomery
97
Genesee
78
Evictions During the Winter Months (November 1 - April 15)
Eviction filings
Code
WITH eviction_filings_with_season AS (
SELECT
DISTINCT indexnumberid,
EXTRACT (YEAR FROM fileddate) AS filed_year,
CASE
WHEN EXTRACT (MONTH FROM fileddate) >= 11 THEN TRUE
WHEN EXTRACT (MONTH FROM fileddate) < 4 THEN TRUE
WHEN EXTRACT (MONTH FROM fileddate) = 4
AND EXTRACT (DAY FROM fileddate) <= 15 THEN TRUE
ELSE FALSE
END AS winter_season
FROM oca_index
WHERE fileddate >= MAKE_DATE(2020 ,1 ,1 )
AND fileddate <= MAKE_DATE(2025 ,12 ,31 )
AND classification IN ('Holdover' , 'Non-Payment' )
AND (propertytype = 'Residential' OR propertytype IS NULL )
)
SELECT
filed_year,
COUNT (indexnumberid) AS all_filings,
SUM (winter_season::int ) AS winter_filings,
100 * ROUND (SUM (winter_season::int )::numeric / COUNT (indexnumberid),3 ) AS winter_filing_pct
FROM eviction_filings_with_season
GROUP BY filed_year
ORDER BY filed_year;
Code
winter_filings_table <- winter_filings |>
# Convert from Postgres int64
mutate (
all_filings = as.numeric (all_filings),
winter_filings = as.numeric (winter_filings)
) |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
set_header_labels (
filed_year = "Year" ,
all_filings = "Annual Filings" ,
winter_filings = "Winter Filings" ,
winter_filing_pct = "Winter Filing Percentage (%)"
) |>
colformat_num (j= 1 ,
big.mark = "" ) |>
colformat_int (j= 2 : 3 ,
big.mark = "," ) |>
align (j= 1 ,
align = "left" ,
part = "all" )
winter_filings_table
Year
Annual Filings
Winter Filings
Winter Filing Percentage (%)
2020
100,546
72,093
71.7
2021
60,491
22,836
37.8
2022
165,470
71,283
43.1
2023
187,034
83,965
44.9
2024
171,311
78,773
46.0
2025
164,597
74,950
45.5
Executed evictions
Code
WITH eviction_exc_with_season AS (
SELECT
DISTINCT i.indexnumberid,
EXTRACT (YEAR FROM w.executiondate) AS executed_year,
CASE
WHEN EXTRACT (MONTH FROM w.executiondate) >= 11 THEN TRUE
WHEN EXTRACT (MONTH FROM w.executiondate) < 4 THEN TRUE
WHEN EXTRACT (MONTH FROM w.executiondate) = 4
AND EXTRACT (DAY FROM w.executiondate) <= 15 THEN TRUE
ELSE FALSE
END AS winter_season
FROM oca_index i
JOIN oca_warrants w on i.indexnumberid= w.indexnumberid
WHERE w.executiondate >= MAKE_DATE(2020 ,1 ,1 )
AND w.executiondate <= MAKE_DATE(2025 ,12 ,31 )
AND i.classification IN ('Holdover' , 'Non-Payment' )
AND (i.propertytype = 'Residential' OR i.propertytype IS NULL )
)
SELECT
executed_year,
COUNT (indexnumberid) AS all_executions,
SUM (winter_season::int ) AS winter_executions,
100 * ROUND (SUM (winter_season::int )::numeric / COUNT (indexnumberid),3 ) AS winter_execution_pct
FROM eviction_exc_with_season
GROUP BY executed_year
ORDER BY executed_year;
Code
winter_executions_table <- winter_executions |>
mutate (all_executions = as.numeric (all_executions),
winter_executions = as.numeric (winter_executions)
) |>
flextable () |>
set_table_properties (width = 1 , layout = "autofit" ) |>
set_header_labels (
executed_year = "Year" ,
all_executions = "Annual Executions" ,
winter_executions = "Winter Executions" ,
winter_execution_pct = "Winter Execution Percentage (%)"
) |>
colformat_num (j= 1 ,
big.mark = "" ) |>
colformat_int (j= 2 : 3 ,
big.mark = "," ) |>
align (j= 1 ,
align = "left" ,
part = "all" )
winter_executions_table
Year
Annual Executions
Winter Executions
Winter Execution Percentage (%)
2020
2,147
2,140
99.7
2021
220
81
36.8
2022
4,462
1,727
38.7
2023
11,863
4,686
39.5
2024
13,334
5,696
42.7
2025
14,160
6,028
42.6