# How do I import students in bulk and refresh the roster each year?

Senior Admins only. Instead of adding students one at a time, click Import CSV from the roster page (or go to /students/import) — Junior Admins won't see this button.

Source: https://www.studentdirectory.app/help/admins/bulk-import-students
Last updated: 2026-11-04

*From the School Administrator manual, "Bulk Importing Students (and the Annual Roster Refresh)".*

**Senior Admins only.** Instead of adding students one at a time, click **Import CSV** from the
roster page (or go to `/students/import`) — Junior Admins won't see this button.

1. Click **Download template (.csv)** for a starter file with the right columns.
2. Required columns: `first_name`, `last_name`.
3. Optional student columns: `graduation_year` (4-digit year, e.g. `2027`), `street`, `city`,
   `state`, `zip`. The older `grade` column (9–12) still works too.
4. Optional guardian columns (up to 2 per student row): `guardian1_title`, `guardian1_first_name`,
   `guardian1_last_name`, `guardian1_email`, `guardian1_phone`, and the same for `guardian2_*`.
   `title` is the relationship (e.g. "Mom", "Dad"). Guardian emails are automatically added to the
   registration allowlist.
5. Choose your filled-in CSV file. Save it as **CSV UTF-8 (Comma delimited)**: a file saved by Windows
   Excel as plain "CSV (Comma delimited)" is refused with a message saying so, because accented
   letters (é, ñ) in it would otherwise be garbled. A ZIP that Excel shortened by dropping its
   leading zero (`07030` saved as `7030`) is read back as `07030`. If you re-upload the **Students**
   download from Data Export, rows marked `is_archived` = `true` (graduated or departed students) are
   skipped, so they stay archived; change the cell to `false` to bring one back. One file can hold your
   whole school: several thousand rows is fine, and you do not need to split it. The only limit is a
   file size of **4 MB** (the hosting service accepts 4.5 MB per upload); a plain CSV is roughly 200
   bytes per student, so that is on the order of 20,000 rows. A larger file shows a message naming the
   limit - remove blank rows and unused columns, and make sure it is saved as CSV rather than Excel.
   Instead of just inserting
   everyone as new, the importer compares
   the file to your **current roster** (including archived/former students, so a returning student
   is recognized rather than duplicated) and sorts every row into:
   - **New** — not on your roster yet, will be added.
   - **Returning, no changes** — already matches your roster exactly; collapsed by default. Any
     guardian listed on that row who isn't on the student's allowlist yet (say, a step-parent added
     to this year's export) is still added when you Apply. A street
     address that's only *written* differently (e.g. "Street" vs "St", "132 East 35th St" vs "132 E
     35 St") isn't treated as a change at all. Gaining an apartment/unit number, or gaining a ZIP+4
     extension, also lands here (not in "Returning, changed") since it's more precise, not a real
     change — expand the section and you'll see a pre-checked (but overridable) checkbox for it, the
     same as any other accepted field.
   - **Returning, changed** — matched an existing student, but a field genuinely differs. Each
     changed field shows the old value crossed out next to the new one (addresses are shown in a
     normalized form so the real difference is easy to spot at a glance), with its own checkbox —
     uncheck any you don't want applied (e.g. keep the address you already have on file). A student
     who was previously archived and reappears in the file is tagged **Re-enrolling**.
   - **Graduating** — an existing student not in the file whose class has already graduated;
     expected, checkbox pre-checked to archive them.
   - **No longer listed** — an existing active student not in the file at all; also pre-checked to
     archive, since this usually means they've left the school. **Archiving never deletes their
     record** — it hides them from the active roster while preserving their history (notes, stars,
     lists, other parents' data), and can be undone from their student page any time.
   - **Needs your decision** — an ambiguous match the importer can't resolve on its own: two
     students who share a name and graduation year, or a student whose name matches an existing
     one but whose graduation year doesn't (shows both years so you can tell if it's really the
     same student, e.g. a grade correction, before deciding). There's no way to resolve this from
     within the importer itself — **Skip this entry** just excludes the row from this Apply run so
     the rest of your import can proceed; it doesn't create or update anything for that student, and
     doesn't fix the underlying mismatch. To actually resolve it, correct the source file and
     re-upload, or edit the student's record directly. **Apply is disabled until every row here is
     either skipped or no longer ambiguous.**
6. If the importer reports that **nothing in the file matched your current roster** on a school that
   already has students, stop and double-check before proceeding — this almost always means a date
   mismatch (e.g. a `grade`-column file uploaded on the other side of the July 1 school-year
   changeover from when it was made), not that every student actually left. You'll need to
   explicitly check "I've checked this is correct" before Apply unlocks in this case.
7. Review the running summary at the bottom of the page, then click **Apply**. A large import can take a
   minute or two. Students and parents are saved first, so they are in your roster even if the page is
   closed or the connection drops partway; if that happens, upload the same file again - students already
   added are recognized, not duplicated. Map locations are looked up after everything is saved. If there
   was not time to place every address, the result says how many are not on the map yet; open **School
   Settings** and click **Re-geocode missing addresses** (repeat if it says more remain). If any newly-linked
   guardian's email already has staff/admin access at your school, the result after Apply lists
   them and their existing role — this is informational only, linking them as a guardian never
   changes that role.
