Memory types
Ten types. Most are a date range with a filter on it. Trip, album, holiday and special day are not, and those are the ones worth reading about. Every type works on a plain NAS: the default install cuts each of them from what Immich already knows (dates, places, faces, favourites).
| Type | Covers | Target | Needs |
|---|---|---|---|
year_in_review | one calendar year | 10 min | nothing extra |
monthly_highlights | one month | 60 s | nothing extra |
season | one season of one year | about 3 min 15 s | nothing extra |
person_spotlight | a range, one person | 60 s a month, capped at 10 min | a named face in Immich |
multi_person | a range, several people | 60 s a month, capped at 10 min | named faces in Immich |
on_this_day | today's date in every earlier year | 45 s | a few years of library |
holiday | one recurring date across several years | 60 s | a few years of library |
trip | one trip found from GPS | 30 s + 10 s an active day | GPS on your pictures, and a home base |
album | one Immich album | 30 s + 10 s an active day | an album |
special_day | one day the library says something happened on | 30 s + 6 s an active hour | nothing, or the discover-days catalogue |
Two setup steps make every type better, not only trips: a home base, so the editor can tell a week away from a week at home, and who's who, so it knows your family from the neighbours. Both take five minutes: Teach it your family.
How long a film runs
The target is where the length starts, not a promise. A film never runs longer than the varied footage its days can fill, counted a day at a time and capped at 30 s a day, so a month with three photographed days gets about 20 s, not a minute. It goes short rather than padding. The run record says what set the length:
| What set it | When |
|---|---|
--duration | you passed a number (or typed a length under Length and pictures in the web UI) |
--short-form | you picked a short-form preset and passed no --duration |
| the material | neither flag, and the period holds pictures |
| the preset floor | neither flag, and the period holds nothing to measure |
A trip and an album count active days: 30 s plus 10 s a day, held between 60 s and 5 min. A special day counts active hours: 30 s plus 6 s an hour, held between 60 s and 3 min, and never fewer than 30 s of pictures on top of its title and ending, however thin the day. Twelve one-minute months do not make a twelve-minute year: the year has its own ten-minute target. How the editor spends those seconds is in Length, quiet weeks and filler.
Filtering by people
Repeating --person means pictures holding every name. --person-match or makes it a union;
the web UI's Pictures with select (all of them together or any of them) is the same switch. For anything else,
--people-expression takes the condition directly:
immich-memories generate --memory-type multi_person --year 2025 \
--people-expression '"Riley" AND ("Casey" OR "Bob")'
AND binds tighter than OR. A person counts as in every picture of an episode (a block of
pictures with no 90-minute gap) where Immich recognised their face at least once, so the back of a
head or a baby asleep on a chest still belongs to a person film. AND means everybody recognised
somewhere in the same episode, not in one frame. The expression replaces --person and
--person-match. The web UI has it under Grouped condition. Trips, albums, person spotlights and any
--birthday run refuse it.
Year in review
A whole calendar year, in capture order, with a title card wherever the month changes.
immich-memories generate --memory-type year_in_review --year 2025
The editor groups the year into stories (a trip, a birthday, a run of ordinary weeks), weighs them against each other and gives each the shots its weight earns. From library to film has the rules. A thin year will not reach 10 minutes and the cut says how far short it landed.
Each month is checked afterwards: a month with worthy material that ends up silent makes the run's
verdict coverage_incomplete. Nothing reserves a slot per month up front. If everything you have is
one summer trip, a season or trip memory fits the material better.
Month dividers appear only when the range spans four months or more. --no-photos takes stills out
of the pool; they are in it by default.
Monthly, season, person, multi-person
Same shape, different scope: pick a range, optionally filter by person, cut.
immich-memories generate --memory-type monthly_highlights --month 7 --year 2025
immich-memories generate --memory-type season --season summer --year 2025
immich-memories generate --memory-type person_spotlight --person "Riley" --year 2025
immich-memories generate --memory-type multi_person --person "Riley" --person "Bob" --year 2025
Season fits a curve through the date range: about 3 min 15 s for three months, the same from the
web UI and the CLI. --duration overrides it. --hemisphere south maps summer onto December to
February.
Person spotlight needs the person named in Immich's face recognition. What makes it a spotlight is the filter: the editor is the same one. Multi-person defaults to AND: an afternoon counts when both were recognised somewhere in it, even if never in one frame. Two people who never share an episode give an empty memory rather than two solo reels. Each window is read once for videos and once for photos, however many people are named. Titles and default filenames say AND or OR, so two runs never overwrite each other.
A people memory with no dates
Leave the dates off a person or multi-person memory and it covers everything up to today, starting on the first day one of its pictures could exist:
immich-memories generate --memory-type multi_person \
--people-expression '("Riley" OR "Bob") AND "Sam"'
The start comes from the birth dates Immich holds, and from birth_date in the people registry where
Immich has none. An AND waits for the youngest person it needs; an OR opens with the oldest it
accepts, and bounds nothing when one of them has no birth date. Two grandparents AND a child born
in 2024 covers 2024 onward, because no older picture can hold the child. runs why on an earlier
picture says where the window came from. Dates you do give are never moved.
A spotlight over more than about 18 months is told as the person, one era per calendar year. Every year that holds a usable picture of them gets one moment before any story gets a second, so the dense recent years cannot take the whole film. Years with no picture of them take no part.
Birthday compilations
--birthday turns a person spotlight into the year of someone's life that ends on the birthday,
plus that birthday in earlier years. For a 21 July birthday and --year 2025 it runs 22 July 2024 to
21 July 2025, so this year's party is in this year's film. Target: 10 minutes.
immich-memories generate --person "Emma" --year 2025 --birthday
The birth date lives in Immich (People, pick the person, edit). Without one a birthday memory
refuses rather than guessing. --birthday 07-21 overrides it for one run, month first; slashed forms
are rejected.
The film reaches back to five earlier birthdays, each ±1 day, for the "look how small you were" cutaways. Most of
those days hold nothing and the run prints one line (history: 2 of 5 earlier windows hold material)
rather than a warning per year. 29 February is celebrated on the 28th in other years.
In the web UI: Person Spotlight, then tick Birthday to birthday, with earlier birthdays. The Birthday (MM-DD) field under it overrides Immich's birth date, and Years back sets how many earlier birthdays it reaches for (five when left empty). For the rolling year without the cutaways, use Custom date range from the day after last year's birthday to this year's. Cut it the night before: a year of one person is a cold run the first time.
On this day
Every earlier year, ±1 day around today, in one 45-second cut. It wants three or more years of library, and it is the obvious one to schedule.
immich-memories generate --memory-type on_this_day --years-back 3
immich-memories generate --memory-type on_this_day --day 2026-08-31 --years-back 20
--day names the anniversary to look back from, so a run can be repeated or compared.
Holiday
A recurrence, not a period: one window per year, the holiday ±2 days, so five Christmases ask Immich for five windows and never for the years between.
immich-memories generate --memory-type holiday --holiday christmas --years-back 5
--holiday is required, --years-back defaults to 5. Ten names resolve for any year:
| Name | Falls on |
|---|---|
new_year | 1 January |
valentines | 14 February |
easter | Western Easter Sunday, computed |
mothers_day | second Sunday of May, or where your home country keeps it |
fathers_day | third Sunday of June, or where your home country keeps it |
halloween | 31 October |
thanksgiving | where the country's public calendar has it (the US: fourth Thursday of November) |
christmas_eve | 24 December |
christmas | 25 December |
new_years_eve | 31 December |
--holiday also takes any public holiday of your country by name (see below), and anything else is
read as MM-DD, for a household's own occasion (--holiday 09-14, the day you moved in). Without --year, the starting year steps back when this year's occasion has not happened
yet. The title is the occasion's name, subtitled "Through the Years" in the film's language, on both
the CLI and the web UI.
The holidays follow the country your home base is in (trips.homebase_latitude and
trips.homebase_longitude); Immich's own geodata says which country that is, so nothing leaves your
server. Each country's public holidays come from the holidays
library, and --holiday accepts their names too (--holiday "ascension day" in Belgium). Without a
home base the US holidays apply, as they always did.
A few family days no public calendar lists are added on top: Valentine's Day, Halloween, Christmas Eve, New Year's Eve, and Mother's and Father's Day, which move by country:
| Country | Mother's Day | Father's Day |
|---|---|---|
US, and any country not listed | second Sunday of May | third Sunday of June |
BE, AT | second Sunday of May | second Sunday of June |
DE | second Sunday of May | Ascension Day |
IT | second Sunday of May | 19 March |
ES, PT | first Sunday of May | 19 March |
FR | last Sunday of May, a week later on Pentecost | third Sunday of June |
GB, IE | three weeks before Easter | third Sunday of June |
AU, NZ | second Sunday of May | first Sunday of September |
MX | 10 May | third Sunday of June |
Only national holidays are read: a holiday kept in one region (a German state, a Canadian province)
is not. A holiday only some families keep, like Eid, is not a public holiday in most countries and
is not in their calendar; give its date as MM-DD.
Something missing? A public holiday belongs in the holidays library upstream. A family day, or a
country whose Mother's or Father's Day differs: open a pull request against
memory_types/date_builders.py, one rule per line.
Trip
Nothing declares a trip. The GPS on your pictures decides where one starts and ends, and each trip gets its own film.
That film is the real renderer over the CC0 fixture library (tests/e2e/fixtures/library, credits
in its CREDITS.md): a week by a lake 590 km from the test home. The satellite fly-over needs
network.map_tiles: true, which is off by default because the tiles come from ArcGIS. With it off,
the title sits on a flat panel. What that switch sends is on Privacy.
Detection is three steps:
- Away from home: a picture counts if its GPS is at least
min_distance_km(50) from home. No GPS, no trip. - Split on gaps: a new trip starts wherever more than
max_gap_days(2) calendar days pass between two pictures, so a rest day does not split a trip. Saturday morning to Monday afternoon is a two-day gap, regardless of the capture times. - Drop the short ones: a trip must span
min_duration_days(2) nights.1catches a weekend.
trips:
homebase_latitude: 48.8566 # required
homebase_longitude: 2.3522 # required
min_distance_km: 50
min_duration_days: 2
max_gap_days: 2
Home base is required. Get it wrong and your own neighbourhood becomes a trip, or real trips
disappear. Drop min_distance_km to about 20 if weekend drives should count.
immich-memories generate --memory-type trip --year 2025 # list what it found
immich-memories generate --memory-type trip --year 2025 --trip-index 2
immich-memories generate --memory-type trip --year 2025 --all-trips
immich-memories generate --memory-type trip --year 2025 --near-date 2025-07-15
Both surfaces read photos and videos, and look a month either side of the year so a trip across New
Year stays whole. --person narrows detection (whose pictures are scanned for GPS, useful when
one phone carries it); the film still takes everything shot in the trip's window. Some cameras strip
GPS, so a library shot on one can look full of holidays and find none.
The name is the smallest place holding at least 85 % of the trip's located pictures, walking up from city to island, region, two regions, country. One step comes before the region: a town holding more than half of the pictures names the trip, so a seaside weekend with a walk to the next town is named after the town, not the province. It comes from the place Immich already stored on each picture, offline:
| The trip | Its name |
|---|---|
| A long weekend, nearly every picture in Las Vegas | Las Vegas, United States |
| Two weeks across Heraklion, Rethymno and Chania | Crete, Greece (French film: Crète, Grèce) |
| Palma and Pollença | Mallorca, Spain |
| A road trip, mostly Utah and Nevada | Utah and Nevada, United States |
| Four states, none of them most of it | United States |
network.geocoding: true lets Nominatim name a one-city or one-region trip in the film's language,
and a trip to a village inside a merged municipality after the village.
It is off by default: it sends coordinates to a third party.
Album
One Immich album instead of a date range. The album is the selection: nothing outside it is considered, nothing inside it is dropped for its date. A shared album counts as your own.
immich-memories generate --from-album "Trip 2025"
immich-memories generate --from-album 59080965-22f0-46a4-be67-135692a9f584
--from-album makes it an album memory, and cannot be combined with --year, --start/--end,
--period, --birthday, --season, --month, --person or another --memory-type. The film is
titled after the album and named album_<slug>.mp4 unless --output names the file. Two albums with one name stop the CLI with the
candidates and their IDs; the web UI lists albums largest first and stores the choice by ID.
Smart albums like Recents can hold tens of thousands of assets. Album mode reads at most
advanced.analysis.max_album_assets per media type (10,000), newest first, and says so. Past that you
probably want a date range.
An album made for one subject
An album you built around one thing (every loaf you baked, every car you drove) can say what that thing is:
immich-memories generate --from-album "Bread" --subject "bread making along the years"
With --subject, every picture in the album stands on that subject. An ordinary film drops a loaf on
a counter with nobody in frame; this one keeps it. Every year the album holds gets at least one shot.
Sharing, the family-viewing holds, duplicates and the length still apply, and the run record lists
each shot that got in on the subject alone (Picking each shot).
--subject needs --from-album and a model reader: the plain NAS reader refuses a written subject.
Special day
The nine types above cover something you named. A special day is one you did not: a day from your own library that a scan flagged, wrote down, and offers back when its anniversary comes round.
immich-memories discover-days # build the catalogue once; it resumes
immich-memories days-due # what falls within three days of today
immich-memories generate --memory-type special_day --day 2016-06-12
discover-days walks the library a month at a time. On a plain NAS, a day is
kept when one recorded fact stands out: it was spent away from home, it holds three or more
favourites, it is mostly video, or it ran long (20 pictures over 6 hours or more) with close family
in it. Each year keeps its strongest automation.special_days_per_year (6), away days first. The
title comes from the day's own place.
The catalogue lives in the store; days-export writes it to a JSON file you can
edit and days-import reads it back. A film covers the day's run, the stretch
of pictures the occasion left, split at five hours of silence rather than at midnight, so a long
night out is not cut at 00:00. It never reaches past its own first and last picture, and a run longer
than 48 hours is not one occasion. window_origin in the run record says what bounded the film.
Three routes bring a day back: auto run offers anniversaries within 3 days (round ones first, a
decade before a seventh), the Special day type on the Memory page offers the whole catalogue, and
generate --day takes any day, catalogued or not. An uncatalogued day is scoped to itself and named
by --title, else by its date.
Catalogue titles name real people and places, so they never reach the command line: automation
passes --day alone and generate re-reads the title. What automation prints is the evidence:
10 years ago today · 289 photos over 18 hours
via special-days catalogue
With a model
A text model adds three things here, and changes nothing else about the types:
discover-daysfirst reads each month's days together, then checks each proposed occasion against that day's own picture descriptions. Both readings must agree it was an occasion; a title alone does not qualify it. No picture is sent. Confirmed occasions need enough varied material for a film, with no six-per-year cap. Unread days remain marked for retry. Rundiscover-days --rescanto check an older catalogue with this confirmation rule.- An uncatalogued special day, and people and occasion films, get a title written from their facts. The reader invents no event name the facts do not carry.
- A month or year gets a light polish on top of the NAS draft. What that polish does and costs is on What a model adds and Make it better.