diff --git a/README.md b/README.md
index 5eef47bcf35b40a424258b3a4158fd3c0a5427be..94a0b6d22f853c21ffa15e37d133b6751aa509b4 100644
--- a/README.md
+++ b/README.md
@@ -145,6 +145,18 @@ Role Variables
 | `funkwhale_custom_pip_packages`         | `[]`                          | A list of additional python packages to download |
 | `funkwhale_custom_settings`             | ``                            | Some Python code to append to `api/config/settings/production.py`. Use funkwhale_custom_settings: |` for multiline code. |
 
+**Installing from source**
+
+If you want to install Funkwhale from source (e.g to try a nonproduction branch, or use your own fork), you use the
+following variables:
+
+| name                                    | Default                                               | Description                                   |
+| --------------------------------------- | ----------------------------------------------------- | --------------------------------------------- |
+| `funkwhale_install_from_source`         | `false`                                               | Install and build Funkwhale from source       |
+| `funkwhale_source_url`                  | `https://dev.funkwhale.audio/funkwhale/funkwhale.git` | URL to the git repository to use              |
+
+Use the `funkwhale_version` variable to control the git tag/branch to checkout.
+
 Supported platforms
 -------------------
 
diff --git a/defaults/main.yml b/defaults/main.yml
index d46d71064bfbc21ddce08074a185aee292d157e0..8e7f4d203a29c9a6a93d5d5070c7a8ea6f00b73e 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -31,3 +31,6 @@ funkwhale_ssl_cert_path:
 funkwhale_ssl_key_path:
 funkwhale_custom_settings:
 funkwhale_custom_pip_packages: []
+funkwhale_install_from_source: false
+funkwhale_source_url: https://dev.funkwhale.audio/funkwhale/funkwhale.git
+funkwhale_node_version: "13"
diff --git a/tasks/funkwhale.yml b/tasks/funkwhale.yml
index 96db81eeb7f0780c287cca8b89448591b3663193..07ea089b8cc269d684e2276834038c813b3abff3 100644
--- a/tasks/funkwhale.yml
+++ b/tasks/funkwhale.yml
@@ -67,10 +67,11 @@
   notify:
     - restart funkwhale
 
+
 - name: Download front-end files
   become: true
   become_user: "{{ funkwhale_username }}"
-  when: funkwhale_frontend_managed
+  when: funkwhale_frontend_managed and not funkwhale_install_from_source
   unarchive:
     src: https://dev.funkwhale.audio/funkwhale/funkwhale/builds/artifacts/{{ funkwhale_version }}/download?job=build_front
     dest: "{{ funkwhale_install_path }}"
@@ -81,6 +82,7 @@
 - name: Download api files
   become: true
   become_user: "{{ funkwhale_username }}"
+  when: not funkwhale_install_from_source
   unarchive:
     src: https://dev.funkwhale.audio/funkwhale/funkwhale/builds/artifacts/{{ funkwhale_version }}/download?job=build_api
     dest: "{{ funkwhale_install_path }}"
@@ -88,6 +90,105 @@
   notify:
     - reload funkwhale
 
+# Install from source
+- name: "Download Funkwhale source"
+  when: funkwhale_install_from_source
+  become: true
+  become_user: "{{ funkwhale_username }}"
+  git:
+    repo: "{{ funkwhale_source_url }}"
+    dest: "{{ funkwhale_install_path }}/src"
+    version: "{{ funkwhale_version }}"
+    force: true
+  notify:
+    - reload funkwhale
+
+- name: Create /front symlink to source
+  when: funkwhale_frontend_managed and funkwhale_install_from_source
+  become: true
+  become_user: "{{ funkwhale_username }}"
+  file:
+    src: "{{ funkwhale_install_path }}/src/front"
+    dest: "{{ funkwhale_install_path }}/front"
+    state: link
+
+- name: Create /api symlink to source
+  when: funkwhale_install_from_source
+  become: true
+  become_user: "{{ funkwhale_username }}"
+  file:
+    src: "{{ funkwhale_install_path }}/src/api"
+    dest: "{{ funkwhale_install_path }}/api"
+    state: link
+
+- name: Create /config symlink in source
+  when: funkwhale_install_from_source
+  become: true
+  become_user: "{{ funkwhale_username }}"
+  file:
+    src: "{{ funkwhale_config_path }}"
+    dest: "{{ funkwhale_install_path }}/src/config"
+    state: link
+
+- name: "Add frontend apt repositories GPG key"
+  become: true
+  when: funkwhale_frontend_managed and funkwhale_install_from_source
+  apt_key:
+    url: "{{ item }}"
+    state: present
+  with_items:
+    - https://dl.yarnpkg.com/debian/pubkey.gpg
+    - https://deb.nodesource.com/gpgkey/nodesource.gpg.key
+
+- name: "Install frontend apt repositories"
+  become: true
+  when: funkwhale_frontend_managed and funkwhale_install_from_source
+  apt_repository:
+    repo: deb https://dl.yarnpkg.com/debian/ stable main
+    state: present
+  with_items:
+    - "deb https://dl.yarnpkg.com/debian/ stable main"
+    - "deb https://deb.nodesource.com/node_{{ funkwhale_node_version }}.x {{ ansible_distribution_release }} main"
+
+- name: "Install frontend build dependencies"
+  become: true
+  when: funkwhale_frontend_managed and funkwhale_install_from_source
+  package:
+    name: "{{ item }}"
+  with_items:
+    - nodejs
+    - yarn
+    - yarn
+
+- name: "Install frontend depencies"
+  become: true
+  when: funkwhale_frontend_managed and funkwhale_install_from_source
+  package:
+    name:
+      - nodejs
+      - yarn
+      - gettext
+      - jq
+
+- name: "Install frontend javascript dependencies"
+  become: true
+  become_user: "{{ funkwhale_username }}"
+  when: funkwhale_frontend_managed and funkwhale_install_from_source
+  yarn:
+    path: "{{ funkwhale_install_path }}/src/front"
+
+- name: "Build front-end"
+  become: true
+  become_user: "{{ funkwhale_username }}"
+  when: funkwhale_frontend_managed and funkwhale_install_from_source
+  command: "yarn build"
+  args:
+    chdir: "{{ funkwhale_install_path }}/src/front"
+  notify:
+    - reload funkwhale
+
+# end of from source related stuff
+
 - name: "Setup virtualenv"
   become: true
   become_user: "{{ funkwhale_username }}"