Your video library starts small. Three recordings, maybe five. You scroll, you find what you need. Then one morning you have forty-seven recordings and no idea which "Product Demo" was for which client.
A flat list stops working fast. Search helps when you remember keywords, but it doesn't help when you're trying to see everything for a project or find all your onboarding videos at once.
We added folders and tags to SendRec. Folders group videos by project or client. Tags cross-label them with categories like "demo", "internal", or "Q1". The two work together — a video lives in one folder but can have up to ten tags.
Why folders AND tags
We considered three approaches: folders only, tags only, or both.
Folders alone force you into a single hierarchy. A demo video for Client A that's also an onboarding walkthrough has to live in one place. Tags alone give you flexibility but no visual structure — everything is still a flat list with colored labels.
Both gives you the best of each. Folders provide structure. Tags provide cross-cutting categorization. A video in the "Client A" folder can also be tagged "onboarding" and "product-demo". Click the folder to see Client A's videos. Click the tag to see all onboarding videos across every client.
The database: three tables, one column
The migration adds three tables and one column:
CREATE TABLE folders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
position INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(user_id, name)
);
CREATE TABLE tags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
color TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(user_id, name)
);
CREATE TABLE video_tags (
video_id UUID NOT NULL REFERENCES videos(id) ON DELETE CASCADE,
tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (video_id, tag_id)
);
ALTER TABLE videos ADD COLUMN folder_id UUID
REFERENCES folders(id) ON DELETE SET NULL;
Folders are single-level by design. No nesting, no tree structures, no recursive CTEs. When you delete a folder, videos become unfiled — ON DELETE SET NULL handles that automatically.
Tags use a junction table. Deleting a tag cascades through video_tags and removes it from all videos. The UNIQUE(user_id, name) constraint on both tables prevents duplicates per user.
The API: ten new endpoints
Folder and tag management follows standard CRUD:
-
GET/POST/PUT/DELETE /api/folders— list, create, rename, delete -
GET/POST/PUT/DELETE /api/tags— same pattern, with an optional hex color
Video assignment is two PUT endpoints:
-
PUT /api/videos/{id}/folder— move to a folder or unfile withnull -
PUT /api/videos/{id}/tags— set the complete tag list (delete-and-replace)
The existing video list endpoint gained two query parameters:
-
?folder_id=uuid— filter by folder -
?folder_id=unfiled— show only videos without a folder -
?tag_id=uuid— filter by tag
These plug into the existing dynamic SQL builder. The pattern was already there for search queries — each filter appends a WHERE clause with a parameterized index:
if folderFilter == "unfiled" {
baseQuery += " AND v.folder_id IS NULL"
} else if folderFilter != "" {
baseQuery += fmt.Sprintf(` AND v.folder_id = $%d`, paramIdx)
args = append(args, folderFilter)
paramIdx++
}
Tags in the list response
Each video in the list now includes its tags. Rather than N+1 queries, we use a JSON aggregate subquery:
COALESCE(
(SELECT json_agg(
json_build_object('id', t.id, 'name', t.name, 'color', t.color)
ORDER BY t.name
)
FROM video_tags vt JOIN tags t ON t.id = vt.tag_id
WHERE vt.video_id = v.id),
'[]'::json
) AS tags_json
One query returns everything. The COALESCE with '[]'::json ensures we always get a valid JSON array, even for videos with no tags. On the Go side, we unmarshal the string into a slice of tag structs.
The sidebar
The Library page gained a left sidebar. It's always visible on desktop (220px fixed width) and wraps horizontally on mobile screens below 640px.
The sidebar contains:
- All Videos — shows everything
- Unfiled — videos not in any folder
- Folders — each with a video count, click to filter
- Tags — each with a colored dot and count, click to filter
Clicking a sidebar item fires a filter change that re-fetches the video list with the appropriate query parameter. The active item gets highlighted.
Inline management
Creating a folder is a click on the "+" button, type a name, press Enter. Same for tags, with an optional color picker. No modals, no separate pages.
Renaming works by clicking the three-dot menu on any sidebar item, selecting "Rename", and editing in place. Delete shows a confirmation since it affects videos.
In the video overflow menu, a new "Organization" section provides a folder dropdown and tag toggle buttons. Changing a folder or toggling a tag takes effect immediately.
Tag chips
Videos display their tags as small pills below the metadata line. Each chip shows a colored dot matching the tag's color and the tag name. They're purely visual — a quick way to see how a video is categorized without opening the overflow menu.
Limits
We kept the limits practical:
- 50 folders per user
- 100 tags per user
- 10 tags per video
- Folder names up to 100 characters
- Tag names up to 50 characters
- Tag colors must be valid hex (
#rrggbb)
What we didn't build
No drag-and-drop reordering for folders (position is set via the API but not exposed in the UI yet). No nested folders. No bulk operations (select multiple videos, move to folder). No tag colors in the overflow menu toggles.
These are all reasonable additions, but they'd add complexity without solving the core problem: finding and grouping recordings. The current implementation covers the common case — organize by project, label by category, filter by either.
Try it
Folders and tags are live at app.sendrec.eu in v1.44.0. Self-hosters get the feature automatically on upgrade — the migration runs on startup.
If you're self-hosting SendRec, check out the self-hosting guide. The new tables are created automatically by the migration system.
Top comments (1)
Great breakdown of how folders and tags can dramatically improve video library usability and scalability. Combining structured folders with flexible tagging is a smart approach, especially as media collections grow and users need faster discovery.”
This aligns with the idea that organizing media into folders and applying tags helps create a more structured and searchable video library, improving navigation and management efficiency.