Unzip it. The message text sits in dated JSON files inside one folder per conversation, and
every message names its author by ID rather than by name, so users.json is what
makes any of it readable. Then search the whole folder at once with grep, a
viewer, or something that can read all of it.
The steps
- Unzip it somewhere you can see.
unzip slack-export.zip -d slack-export. Every public channel becomes a folder named after the channel; private channels, DMs and group DMs become folders named by ID. - Read the index files first. At the top level you get
channels.jsonfor public channels,groups.jsonfor private ones,dms.json,mpims.jsonfor group DMs,users.json(org_users.jsonon Enterprise),integration_logs.json,canvases.jsonandfile_conversations.json. Slack's own guidance is that "you'll need to use both the channel and reference files to find a specific conversation". - Build the ID-to-name map. A message carries
"user": "U024BE7LH", never a display name:jq -r '.[] | [.id, .name] | @tsv' users.json > names.tsv. - Search across every day file at once.
grep -ril "mobile build" slack-export/gives you the channel and the date, because the date is the filename. - Read the hit.
jq -r '.[] | [.ts, .user, .text] | @tsv' slack-export/eng-planning/2026-08-14.json. Each message hastype,user,textandts, the Unix timestamp it was posted at.
Four things that will trip you up
- The files are not in the file export. Slack is explicit: "Slack export files in JSON format do not contain any files from the workspace." What you get instead is URLs pointing back at Slack. A zip you are keeping because the workspace might go away does not contain the attachments.
tsis a string, not a date. It is a Unix timestamp with a fractional part, and it doubles as the message's ID. Thread replies point at their parent withthread_ts, so a reply read on its own has no visible context.- A folder name is not always a channel name. DMs and private channels are
named by ID.
dms.jsonandgroups.jsonare how you find out which is which. - Renamed channels. The folder carries the name at export time, not the name people used in the message you are looking for.
When grep is not enough
grep finds a word. It does not answer "when did we decide to drop the mobile
build, and why" — that answer is spread over three threads in two channels, and the word
"decide" may appear in none of them.
For that you need something that can read the whole folder and keep its own notes. Two honest options: a local model via Ollama pointed at the directory, or a coding CLI working in the folder. Both keep the archive where it is. Uploading a four-year workspace export to a web viewer to find one sentence is the trade people make without thinking about it, and it is the one trade this file does not require.
Nico's showcased version of this job is exactly that: four years of history, answerable, without granting anyone a workspace token and without the zip leaving the Mac.
← All notes