Tracker / LocalSearch DB: GNOME File Index on Linux
GNOME's Tracker and LocalSearch file index on Linux: SQLite databases listing indexed files, their timestamps and extracted content for a user's home.
- Location
- ~/.cache/tracker3/files/
- Proves
- Which files existed in indexed folders, with name, size, MAC times and extracted metadata as last seen by the indexer
- Timestamps
- Unix epoch seconds (UTC) as integers, or ISO 8601 text when an offset or sub-second part must be kept
- Access
- Any user for own cache; root for other users
- Retention
- Mirrors the indexed tree; entries removed when the indexer processes a deletion
- Collection
- UAC, cp -a, tar
Tools
Compare all toolsWhat it is
GNOME desktops ship a file indexer that crawls the user's files, extracts metadata and text, and stores the result in a SPARQL triple store backed by SQLite. It powers search in the Files app (Nautilus), the Activities overview and apps such as Music or Photos. The indexer was called Tracker (tracker-miner-fs); in LocalSearch 3.8 (GNOME 47, 2024) the miners were renamed LocalSearch and the database library Tracker SPARQL became TinySPARQL. The on-disk cache directory kept its tracker3 name.
For an investigator it is a second, independent listing of files in the user's home with their timestamps and sizes, sometimes with extracted text, maintained by a process the user rarely thinks about.
Where it lives
| Generation | Path | Notes |
|---|---|---|
| Tracker 3 and LocalSearch | ~/.cache/tracker3/files/ | $XDG_CACHE_HOME/tracker3/files/; meta.db plus one database per named graph |
| Tracker 3 graph files | http%3A%2F%2Ftracker.api.gnome.org%2Fontology%2Fv3%2Ftracker%23FileSystem.db | Percent-encoded graph IRI; siblings for Audio, Documents, Pictures, Software, Video |
| Tracker 3 errors | ~/.cache/tracker3/files/errors/ | Records of files the extractor failed on |
| LocalSearch 3.11+ removable media | .localsearch3/ at the root of the device | Only when removable indexing is enabled (off by default) |
| Tracker 2 (older GNOME 3 releases) | ~/.cache/tracker/meta.db | Single database; journal and logs under ~/.local/share/tracker/ |
Paths do not depend on the distribution family. What varies is whether the indexer is installed and running: it is commonly installed with GNOME desktops and usually absent on servers and other desktops. Some sandboxed or Flatpak builds are compiled with a different cache location, so search the whole home for meta.db.
What it proves
- That a file with a given path, name and size existed in an indexed location when the indexer last processed it.
- The file's modification, access and (where the filesystem and GLib expose it) creation time as the indexer saw them.
- Extracted metadata: document titles and authors, EXIF data, audio tags, page counts, and plain text content for supported documents.
- Which folders were indexing roots and which removable or network volumes were known.
It does not prove that a user opened a file (indexing is automatic), and it is not a history: an entry is updated in place when the file changes. When the indexer sees a deletion, it removes the entry, so a deleted file survives only if the indexer did not process the change (not running, excluded, crash) or as residue in SQLite free pages and -wal files.
Key fields
The store follows the NEPOMUK-based ontology. These properties matter most for files:
| Property | Meaning |
|---|---|
nie:url | File URI (file:///home/...) of the data object |
nfo:fileName | File name |
nfo:fileSize | Size in bytes |
nfo:fileLastModified | File mtime |
nfo:fileLastAccessed | File atime |
nfo:fileCreated | File birth time, when GLib and the filesystem expose it |
nie:plainTextContent | Extracted text of a document (content graphs such as Documents) |
nie:title, nfo:pageCount, EXIF and audio properties | Extracted metadata |
In SQLite, each class is stored as a table named after the class (such as nfo:FileDataObject) with one column per single-valued property, and multi-valued properties get Class_property tables. meta.db also holds the Resource table that maps every row ID to its IRI, and the Graph table listing named graphs. Identifiers contain colons, so quote them in SQL, and list the real table names with .tables before querying.
Timestamps
TinySPARQL stores an xsd:dateTime as an integer Unix timestamp (UTC seconds) when that is lossless, and as ISO 8601 text when the value has a UTC offset or microseconds. Expect both forms in the same column and normalise them:
-- adjust the table name to what .tables shows in the graph database
SELECT CASE typeof(v) WHEN 'integer' THEN datetime(v, 'unixepoch') ELSE v END AS utc
FROM (SELECT "nfo:fileLastModified" AS v FROM "nfo:FileDataObject" LIMIT 5);
The time values are the file's own metadata. The database files' mtime only tells you when the indexer last wrote.
Retention
The index tracks the live filesystem: new files are added, changed files updated and deleted files removed as the miner is notified or recrawls on start. localsearch reset (formerly tracker3 reset) or deleting the cache discards everything. Configuration lives in GSettings schema org.freedesktop.Tracker3.Miner.Files:
index-recursive-directories: since LocalSearch 3.11 the default is the whole home directory; earlier releases indexed a set of XDG user folders instead.index-removable-devicesandindex-optical-discs: both default to false.ignored-directories-with-content: folders containing.trackerignore,.git,.hgor.nomediaare skipped.org.freedesktop.Tracker3.Extractmax-bytes: at most 1 MiB of UTF-8 text is extracted per file.
Collection
UAC's files/system/tracker.yaml (in ir_triage) copies meta.db* and the graph databases from ~/.cache/tracker3/files for each user. It does not cover Tracker 2 or removable-media databases, so add those by hand. Stop or avoid touching the user session first if you can: the indexer writes continuously.
cd /mnt/evidence
find home root -path '*/.cache/tracker*' \( -name '*.db' -o -name '*.db-wal' -o -name '*.db-shm' -o -name '*.journal' \) \
-print0 | tar --null -T - -czf tracker.tgz
Always keep the -wal and -shm companions with each database.
Parsing
Work on copies. The supported way to read the store is SPARQL through the TinySPARQL CLI, which opens a database directory read-only unless --update is given:
tinysparql query --database ./tracker3/files \
'SELECT ?url ?size ?mtime ?atime WHERE {
?f a nfo:FileDataObject ; nie:url ?url ; nfo:fileSize ?size ; nfo:fileLastModified ?mtime .
OPTIONAL { ?f nfo:fileLastAccessed ?atime } } ORDER BY ?mtime'
The files are also ordinary SQLite databases, so sqlite3 works for bulk export and for inspecting free pages; attach the graph databases to meta.db so Resource IDs resolve.
On a live system, localsearch info <file> and localsearch search <term> query the running index.
Investigator tips
- Compare indexed URLs with a filesystem listing of the image: indexed files that no longer exist point to deletions the indexer missed, and give you name, size and times for them (see ext4 deleted files).
- Carve SQLite free pages and the
-walfile for older row versions of deleted or changed entries. - Extracted
nie:plainTextContentcan hold the first part of a document's text even when the document itself is gone or encrypted later. - Removable and network volumes known to the index help tie USB media to a user; correlate with udev and USB logs.
- Pair with recently-used.xbel: the index shows a file existed, the recent list shows it was opened.
- A user who disabled indexing (settings or
.trackerignorefiles) leaves a gap, not a clue of wrongdoing by itself.