diff --git a/app/factory.py b/app/factory.py
index 71dc66c0012f31fe5ee46ffc45c2fe649ba3a371..85e70078b6ffd8dbb89f7bbd830947f2a928c359 100644
--- a/app/factory.py
+++ b/app/factory.py
@@ -57,6 +57,7 @@ def create_app(config=None):
     app.config.update(config or {})
 
     app.jinja_env.filters["datetimeformat"] = utils.format_datetime
+    app.jinja_env.filters["toyaml"] = utils.pretty_yaml
 
     if not app.debug:
         import logging
diff --git a/app/fields.py b/app/fields.py
new file mode 100644
index 0000000000000000000000000000000000000000..a5ed4fb40d699e07bd2abae891f98c7a0ae8c5c7
--- /dev/null
+++ b/app/fields.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+"""
+app.fields
+~~~~~~~~~~
+
+This module defines extra WTForms fields
+
+:copyright: (c) 2018 European Spallation Source ERIC
+:license: BSD 2-Clause, see LICENSE for more details.
+
+"""
+import yaml
+from wtforms import TextAreaField
+
+
+class YAMLField(TextAreaField):
+    """This field represents an HTML ``<textarea>`` used to input YAML"""
+
+    def _value(self):
+        return yaml.safe_dump(self.data, default_flow_style=False) if self.data else ""
+
+    def process_formdata(self, valuelist):
+        if valuelist:
+            try:
+                self.data = yaml.safe_load(valuelist[0])
+            except yaml.YAMLError:
+                raise ValueError("This field contains invalid YAML")
+        else:
+            self.data = None
+
+    def pre_validate(self, form):
+        super().pre_validate(form)
+        if self.data:
+            try:
+                yaml.safe_dump(self.data)
+            except yaml.YAMLError:
+                raise ValueError("This field contains invalid YAML")
diff --git a/app/models.py b/app/models.py
index ed3672993ef3ea71a25caa148f74f45f9b93bb39..f7cda977e6643f8bc51ceea647eff76f6af3b637 100644
--- a/app/models.py
+++ b/app/models.py
@@ -10,6 +10,7 @@ This module implements the models used in the app.
 
 """
 import ipaddress
+import json
 import string
 import qrcode
 import itertools
@@ -750,6 +751,7 @@ class Host(CreatedMixin, db.Model):
     device_type_id = db.Column(
         db.Integer, db.ForeignKey("device_type.id"), nullable=False
     )
+    ansible_vars = db.Column(postgresql.JSONB)
 
     interfaces = db.relationship("Interface", backref="host")
     items = db.relationship("Item", backref="host")
@@ -811,6 +813,7 @@ class Host(CreatedMixin, db.Model):
                 "description": self.description,
                 "items": [str(item) for item in self.items],
                 "interfaces": [str(interface) for interface in self.interfaces],
+                "ansible_vars": json.dumps(self.ansible_vars),
             }
         )
         return d
diff --git a/app/network/forms.py b/app/network/forms.py
index b564519571409749202c3a0d1422e7b18dd581a5..be0d235e07a5a891085e2ad0aaa66b2e41c39a7d 100644
--- a/app/network/forms.py
+++ b/app/network/forms.py
@@ -31,6 +31,7 @@ from ..validators import (
     MAC_ADDRESS_RE,
     NoValidateSelectField,
 )
+from ..fields import YAMLField
 from .. import utils, models
 
 
@@ -139,6 +140,10 @@ class HostForm(CSEntryForm):
     )
     description = TextAreaField("Description")
     device_type_id = SelectField("Device Type")
+    ansible_vars = YAMLField(
+        "Ansible vars",
+        description="Enter variables in YAML format. See https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html",
+    )
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
diff --git a/app/network/views.py b/app/network/views.py
index c0373ed2f0cb290ba1ceb8dab1a819bbd8244c8b..5487392b47164426951e294715e7b0895116b65f 100644
--- a/app/network/views.py
+++ b/app/network/views.py
@@ -67,6 +67,7 @@ def create_host():
             name=form.name.data,
             device_type_id=form.device_type_id.data,
             description=form.description.data or None,
+            ansible_vars=form.ansible_vars.data or None,
         )
         # The total number of tags will always be quite small
         # It's more efficient to retrieve all of them in one query
@@ -138,6 +139,7 @@ def edit_host(name):
         host.name = form.name.data
         host.device_type_id = form.device_type_id.data
         host.description = form.description.data or None
+        host.ansible_vars = form.ansible_vars.data or None
         current_app.logger.debug(f"Trying to update: {host!r}")
         try:
             db.session.commit()
diff --git a/app/static/js/hosts.js b/app/static/js/hosts.js
index 9bfc6c6466416a5354234b7da4c83b0d028b1172..463fff207cf6b6297481022886609108ee7e400a 100644
--- a/app/static/js/hosts.js
+++ b/app/static/js/hosts.js
@@ -1,5 +1,13 @@
 $(document).ready(function() {
 
+  if( $("#hostForm").length || $("#editHostForm").length ) {
+    var hostVarsEditor = CodeMirror.fromTextArea(ansible_vars, {
+        lineNumbers: true,
+        mode: "yaml"
+    });
+    hostVarsEditor.setSize(null, 120);
+  }
+
   function set_default_ip() {
     // Retrieve the first available IP for the selected network
     // and update the IP field
diff --git a/app/templates/network/create_host.html b/app/templates/network/create_host.html
index 0190418ba8d286c01a352f13865e3cdb7ba35252..f811580a789e71d32188987cd42e86e7a59832ec 100644
--- a/app/templates/network/create_host.html
+++ b/app/templates/network/create_host.html
@@ -16,6 +16,7 @@
     {{ render_field(form.mac_address) }}
     {{ render_field(form.cnames_string) }}
     {{ render_field(form.tags, class_="selectpicker") }}
+    {{ render_field(form.ansible_vars) }}
     <div class="form-group row">
       <div class="col-sm-10">
         <button type="submit" class="btn btn-primary">Submit</button>
diff --git a/app/templates/network/edit_host.html b/app/templates/network/edit_host.html
index 866f12a606991e7514c9e38850b19a0323528a22..eadd2440ba633bd812d53cfa5ab444e55107a562 100644
--- a/app/templates/network/edit_host.html
+++ b/app/templates/network/edit_host.html
@@ -21,6 +21,7 @@
     {{ render_field(form.name, class_="text-lowercase") }}
     {{ render_field(form.device_type_id) }}
     {{ render_field(form.description) }}
+    {{ render_field(form.ansible_vars) }}
     <div class="form-group row">
       <div class="col-sm-10">
         <button type="submit" class="btn btn-primary">Submit</button>
diff --git a/app/templates/network/view_host.html b/app/templates/network/view_host.html
index 72e97a928eea85de9fe72e0e9d3871d8d6425f3d..8e3cd004217c6bceaf52dac174c2d1853ed22503 100644
--- a/app/templates/network/view_host.html
+++ b/app/templates/network/view_host.html
@@ -38,6 +38,10 @@
         <dd class="col-sm-9">{{ host.user }}</dd>
         <dt class="col-sm-3">Created at</dt>
         <dd class="col-sm-9">{{ host.created_at | datetimeformat }}</dd>
+        {% if host.ansible_vars %}
+        <dt class="col-sm-3">Ansible vars</dt>
+        <dd class="col-sm-9"><pre>{{ host.ansible_vars | toyaml }}</pre></dd>
+        {% endif %}
       </dl>
     </div>
     {% if host.device_type.name.startswith('Virtual') and current_user.is_admin %}
diff --git a/app/utils.py b/app/utils.py
index 758e4d436d15bc2aa9ba4907d538bb9a6b8738ce..8191098f06c8d3b27d9aed0a705796b0b8b59ba2 100644
--- a/app/utils.py
+++ b/app/utils.py
@@ -15,6 +15,7 @@ import io
 import random
 import sqlalchemy as sa
 import dateutil.parser
+import yaml
 from flask import current_app
 from flask.globals import _app_ctx_stack, _request_ctx_stack
 from flask_login import current_user
@@ -225,6 +226,14 @@ def format_datetime(value, format="%Y-%m-%d %H:%M"):
     return value.strftime(format)
 
 
+def pretty_yaml(value):
+    """Pretty print yaml
+
+    Function used as a jinja2 filter
+    """
+    return yaml.safe_dump(value, default_flow_style=False)
+
+
 def trigger_core_services_update():
     """Trigger a job to update the core services on the TN (DNS and DHCP)
 
diff --git a/migrations/versions/d67f43bbd675_add_ansible_vars_column.py b/migrations/versions/d67f43bbd675_add_ansible_vars_column.py
new file mode 100644
index 0000000000000000000000000000000000000000..2912d3fe442ac50dfefff5b0d438ac9b5555910f
--- /dev/null
+++ b/migrations/versions/d67f43bbd675_add_ansible_vars_column.py
@@ -0,0 +1,29 @@
+"""Add ansible_vars column
+
+Revision ID: d67f43bbd675
+Revises: a9442567c6dc
+Create Date: 2018-07-10 11:39:17.955468
+
+"""
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import postgresql
+
+# revision identifiers, used by Alembic.
+revision = "d67f43bbd675"
+down_revision = "a9442567c6dc"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.add_column(
+        "host",
+        sa.Column(
+            "ansible_vars", postgresql.JSONB(astext_type=sa.Text()), nullable=True
+        ),
+    )
+
+
+def downgrade():
+    op.drop_column("host", "ansible_vars")
diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py
index af30acc2a427e288a21bea705555301f4ffab73d..09d10b2e1f98b766539b824bd42121c0926cf537 100644
--- a/tests/functional/test_api.py
+++ b/tests/functional/test_api.py
@@ -1098,6 +1098,13 @@ def test_get_hosts(client, host_factory, readonly_token):
     check_input_is_subset_of_response(response, (host1.to_dict(), host2.to_dict()))
 
 
+def test_get_hosts_with_ansible_vars(client, host_factory, readonly_token):
+    host_factory(ansible_vars={"foo": "hello", "mylist": [1, 2, 3]})
+    response = get(client, f"{API_URL}/network/hosts", token=readonly_token)
+    assert response.status_code == 200
+    assert response.json[0]["ansible_vars"] == '{"foo": "hello", "mylist": [1, 2, 3]}'
+
+
 def test_create_host(client, device_type_factory, user_token):
     device_type = device_type_factory(name="Virtual")
     # check that name and device_type are  mandatory
@@ -1125,6 +1132,7 @@ def test_create_host(client, device_type_factory, user_token):
         "description",
         "items",
         "interfaces",
+        "ansible_vars",
         "created_at",
         "updated_at",
         "user",
@@ -1160,6 +1168,20 @@ def test_create_host_with_items(client, item_factory, device_type_factory, user_
     assert models.Item.query.get(item2.id).host_id == host.id
 
 
+def test_create_host_with_ansible_vars(client, device_type_factory, user_token):
+    device_type = device_type_factory(name="VirtualMachine")
+    data = {
+        "name": "my-host",
+        "device_type": device_type.name,
+        "ansible_vars": {"foo": "hello", "mylist": [1, 2, 3]},
+    }
+    response = post(client, f"{API_URL}/network/hosts", data=data, token=user_token)
+    assert response.status_code == 201
+    assert response.json["ansible_vars"] == '{"foo": "hello", "mylist": [1, 2, 3]}'
+    host = models.Host.query.filter_by(name="my-host").first()
+    assert host.ansible_vars == {"foo": "hello", "mylist": [1, 2, 3]}
+
+
 def test_create_host_as_consultant(
     client, item_factory, device_type_factory, consultant_token
 ):