--- /dev/null
+ALTER TABLE files ADD COLUMN tags TEXT NOT NULL DEFAULT "";
 
   flags INTEGER NOT NULL DEFAULT 0,
   yt_id TEXT,
   last_update TEXT NOT NULL,
+  tags TEXT NOT NULL DEFAULT "",
   FOREIGN KEY (yt_id) REFERENCES yt_videos(id)
 );
 
 <tr><th>path:</th><td>{{file.rel_path}}</td></tr>
 <tr><th>YouTube ID:</th><td><a href="/{{page_names.yt_result}}/{{file.yt_id}}">{{file.yt_id}}</a></tr>
 <tr><th>present:</th><td>{% if file.present %}<a href="/{{page_names.download}}/{{file.yt_id}}">yes</a>{% else %}no{% endif %}</td></tr>
-<tr><th>flags:</th><td class="flags">
+<tr>
+<th>flags:</th>
+<td class="flags">
 {% for flag_name in flag_names %}
-{{ flag_name }}: <input type="checkbox" name="{{flag_name}}" {% if file.is_flag_set(flag_name) %}checked {% endif %} /><br />
+{{ flag_name }}: <input type="checkbox" name="flags" value="{{flag_name}}" {% if file.is_flag_set(flag_name) %}checked {% endif %} /><br />
 {% endfor %}
-</td></tr>
+</td>
+</tr>
+<tr>
+<th>tags</th>
+<td>
+{% for tag in file.tags %}
+<input type="checkbox" name="tags" value="{{tag}}" checked /> {{tag}}<br />
+{% endfor %}
+<input name="tags" />
+</td>
+</tr>
 </table>
 <input type="submit" />
 </form>
 
 
 SqlText = NewType('SqlText', str)
 
-EXPECTED_DB_VERSION = 5
+EXPECTED_DB_VERSION = 6
 PATH_DB = PATH_APP_DATA.joinpath('db.sql')
 SQL_DB_VERSION = SqlText('PRAGMA user_version')
 PATH_MIGRATIONS = PATH_APP_DATA.joinpath('migrations')
 
         if PAGE_NAMES['files'] == page_name:
             self._receive_files_command(list(postvars.keys())[0])
         elif PAGE_NAMES['file'] == page_name:
-            self._receive_video_flag(Hash.from_b64(toks_url[2]),
-                                     [FlagName(k) for k in postvars])
+            self._receive_file_data(Hash.from_b64(toks_url[2]),
+                                    postvars)
         elif PAGE_NAMES['yt_queries'] == page_name:
             self._receive_yt_query(QueryText(postvars['query'][0]))
 
             self.server.player.inject_and_play(file)
         self._redirect(Path('/'))
 
-    def _receive_video_flag(self,
-                            digest: Hash,
-                            flag_names: list[FlagName]
-                            ) -> None:
+    def _receive_file_data(self,
+                           digest: Hash,
+                           postvars: dict[str, list[str]]
+                           ) -> None:
+        flag_names = [FlagName(f) for f in postvars.get('flags', [])]
         with DbConn() as conn:
             file = VideoFile.get_one(conn, digest)
             file.set_flags([FILE_FLAGS[name] for name in flag_names])
+            file.tags = postvars.get('tags', [])
             file.save(conn)
             conn.commit()
         file.ensure_absence_if_deleted()
 
     _Migration(2, Path('2_add_files_sha512.sql'), _mig_2_calc_digests),
     _Migration(3, Path('3_files_redo.sql')),
     _Migration(4, Path('4_add_files_sha512_blob.sql'), _mig_4_convert_digests),
-    _Migration(5, Path('5_files_redo.sql'))
+    _Migration(5, Path('5_files_redo.sql')),
+    _Migration(6, Path('6_add_files_tags.sql'))
 ]
 
     """Collects data about downloaded files."""
     id_name = 'digest'
     _table_name = 'files'
-    _cols = ('digest', 'rel_path', 'flags', 'yt_id', 'last_update')
+    _cols = ('digest', 'rel_path', 'flags', 'yt_id', 'last_update', 'tags_str')
     last_update: DatetimeStr
     rel_path: Path
     digest: Hash
                  rel_path: Path,
                  flags: FlagsInt = FlagsInt(0),
                  yt_id: Optional[YoutubeId] = None,
-                 last_update: Optional[DatetimeStr] = None
+                 last_update: Optional[DatetimeStr] = None,
+                 tags_str: str = ''
                  ) -> None:
         self.rel_path = rel_path
         self.digest = digest if digest else Hash.from_file(self.full_path)
-        self.yt_id = yt_id
         self.flags = flags
+        self.tags = tags_str.split(',') if tags_str else []
+        self.yt_id = yt_id
         if last_update is None:
             self._renew_last_update()
         else:
             raise NotFoundException(f'no entry for file to Youtube ID {yt_id}')
         return cls._from_table_row(row)
 
+    @property
+    def tags_str(self):
+        """Return self.tags joined by ','."""
+        return ','.join(self.tags)
+
     @property
     def full_path(self) -> Path:
         """Return self.rel_path suffixed under PATH_DOWNLOADS."""