diff --git a/backend/metagenedb/apps/catalog/migrations/0010_genefunction.py b/backend/metagenedb/apps/catalog/migrations/0010_genefunction.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f44becba32562d4ef680af81b37bbaa7f671e4f
--- /dev/null
+++ b/backend/metagenedb/apps/catalog/migrations/0010_genefunction.py
@@ -0,0 +1,37 @@
+# Generated by Django 2.2.5 on 2019-09-12 13:08
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+from metagenedb.common.utils.chunks import generate_chunks
+
+
+def copy_gene_functions(apps, schema_editor):
+    Gene = apps.get_model('catalog', 'Gene')
+    GeneFunction = apps.get_model('catalog', 'GeneFunction')
+    OldGeneFunctions = Gene.functions.through
+    for chunk in generate_chunks(OldGeneFunctions.objects.all(), 500):
+        new_objs = [GeneFunction(gene=item.gene, function=item.function) for item in chunk]
+        GeneFunction.objects.bulk_create(new_objs)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('catalog', '0009_meta_unique'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='GeneFunction',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('function', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='catalog.Function')),
+                ('gene', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='catalog.Gene')),
+            ],
+            options={
+                'unique_together': {('gene', 'function')},
+            },
+        ),
+        migrations.RunPython(copy_gene_functions)
+    ]
diff --git a/backend/metagenedb/apps/catalog/migrations/0011_change_through_genefunction.py b/backend/metagenedb/apps/catalog/migrations/0011_change_through_genefunction.py
new file mode 100644
index 0000000000000000000000000000000000000000..82fb137a3f639e1a6732a67d6e3112f98557faa1
--- /dev/null
+++ b/backend/metagenedb/apps/catalog/migrations/0011_change_through_genefunction.py
@@ -0,0 +1,23 @@
+# Generated by Django 2.2.5 on 2019-09-12 13:43
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('catalog', '0010_genefunction'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='gene',
+            name='functions',
+            field=models.ManyToManyField(to='catalog.Function'),
+        ),
+        migrations.AddField(
+            model_name='gene',
+            name='functions',
+            field=models.ManyToManyField(through='catalog.GeneFunction', to='catalog.Function'),
+        ),
+    ]
diff --git a/backend/metagenedb/apps/catalog/models/gene.py b/backend/metagenedb/apps/catalog/models/gene.py
index 802ef9ffe0d949d50a428f6535b4539ec5f21040..453910d17bc8f6f294027ba448f4c61d63e6191e 100644
--- a/backend/metagenedb/apps/catalog/models/gene.py
+++ b/backend/metagenedb/apps/catalog/models/gene.py
@@ -7,7 +7,7 @@ class Gene(models.Model):
     gene_name = models.CharField(max_length=100, unique=True)
     gene_id = models.SlugField(max_length=100, db_index=True, unique=True)
     length = models.PositiveIntegerField()
-    functions = models.ManyToManyField(Function)
+    functions = models.ManyToManyField(Function, through='GeneFunction')
     taxonomy = models.ForeignKey(
         'Taxonomy', related_name='genes',
         on_delete=models.SET_NULL,
@@ -19,3 +19,15 @@ class Gene(models.Model):
 
     class Meta:
         ordering = ['-gene_id']
+
+class GeneFunction(models.Model):
+    gene = models.ForeignKey(Gene, on_delete=models.CASCADE)
+    function = models.ForeignKey(Function, on_delete=models.CASCADE)
+
+    def __str__(self):
+        return f"{self.gene.gene_id} <-> {self.function.function_id}"
+
+    class Meta:
+        unique_together = [
+            'gene', 'function'
+        ]