diff --git a/app/models.py b/app/models.py
index ed5d6ed62f343d7d546a2783fc754a843c0ebcbb..8ce4e5d7aae736a456bbabc0652da5ad25e1def6 100644
--- a/app/models.py
+++ b/app/models.py
@@ -840,7 +840,7 @@ class ItemComment(CreatedMixin, db.Model):
 
 class Network(CreatedMixin, db.Model):
     vlan_name = db.Column(CIText, nullable=False, unique=True)
-    vlan_id = db.Column(db.Integer, nullable=False, unique=True)
+    vlan_id = db.Column(db.Integer, nullable=True, unique=True)
     address = db.Column(postgresql.CIDR, nullable=False, unique=True)
     first_ip = db.Column(postgresql.INET, nullable=False, unique=True)
     last_ip = db.Column(postgresql.INET, nullable=False, unique=True)
@@ -1571,8 +1571,8 @@ class Domain(CreatedMixin, db.Model):
 class NetworkScope(CreatedMixin, db.Model):
     __tablename__ = "network_scope"
     name = db.Column(CIText, nullable=False, unique=True)
-    first_vlan = db.Column(db.Integer, nullable=False, unique=True)
-    last_vlan = db.Column(db.Integer, nullable=False, unique=True)
+    first_vlan = db.Column(db.Integer, nullable=True, unique=True)
+    last_vlan = db.Column(db.Integer, nullable=True, unique=True)
     supernet = db.Column(postgresql.CIDR, nullable=False, unique=True)
     domain_id = db.Column(db.Integer, db.ForeignKey("domain.id"), nullable=False)
     description = db.Column(db.Text)
@@ -1603,6 +1603,8 @@ class NetworkScope(CreatedMixin, db.Model):
 
         The range is defined by the first and last vlan
         """
+        if self.first_vlan is None or self.last_vlan is None:
+            return []
         return range(self.first_vlan, self.last_vlan + 1)
 
     def used_vlans(self):
@@ -1610,6 +1612,8 @@ class NetworkScope(CreatedMixin, db.Model):
 
         The list is sorted
         """
+        if self.first_vlan is None or self.last_vlan is None:
+            return []
         return sorted(network.vlan_id for network in self.networks)
 
     def available_vlans(self):
diff --git a/app/network/forms.py b/app/network/forms.py
index ad7b7a1e7c0bbe6574b132acba1eb37561d7897e..2b5422e8c56d9fa3946a1ef2d6fb717057dfb2ac 100644
--- a/app/network/forms.py
+++ b/app/network/forms.py
@@ -92,8 +92,8 @@ class NetworkScopeForm(CSEntryForm):
         ],
     )
     description = TextAreaField("Description")
-    first_vlan = IntegerField("First vlan")
-    last_vlan = IntegerField("Last vlan")
+    first_vlan = IntegerField("First vlan", validators=[validators.optional()])
+    last_vlan = IntegerField("Last vlan", validators=[validators.optional()])
     supernet = StringField(
         "Supernet", validators=[validators.InputRequired(), IPNetwork()]
     )
@@ -115,7 +115,9 @@ class NetworkForm(CSEntryForm):
             Unique(models.Network, column="vlan_name"),
         ],
     )
-    vlan_id = NoValidateSelectField("Vlan id", choices=[])
+    vlan_id = NoValidateSelectField(
+        "Vlan id", choices=[], coerce=utils.coerce_to_str_or_none
+    )
     description = TextAreaField("Description")
     prefix = NoValidateSelectField("Prefix", choices=[])
     address = NoValidateSelectField("Address", choices=[])
diff --git a/app/network/views.py b/app/network/views.py
index 60860d444c04417cbcd6f4154472b457fc65e874..7b4895eec541ba5d8ac2418a0d6d63f8f45d0f67 100644
--- a/app/network/views.py
+++ b/app/network/views.py
@@ -665,6 +665,10 @@ def retrieve_scope_defaults(scope_id):
         }
     else:
         vlans = [vlan_id for vlan_id in scope.available_vlans()]
+        if vlans:
+            selected_vlan = vlans[0]
+        else:
+            selected_vlan = ""
         prefixes = scope.prefix_range()
         default_prefix = current_app.config["NETWORK_DEFAULT_PREFIX"]
         if default_prefix in prefixes:
@@ -674,7 +678,7 @@ def retrieve_scope_defaults(scope_id):
         data = {
             "vlans": vlans,
             "prefixes": prefixes,
-            "selected_vlan": vlans[0],
+            "selected_vlan": selected_vlan,
             "selected_prefix": selected_prefix,
             "domain_id": scope.domain_id,
         }
diff --git a/app/static/js/csentry.js b/app/static/js/csentry.js
index 78d6775491a2d224231aff537be39298f40051cf..d23fe0e018b330572645c20e9a43601b647b4fed 100644
--- a/app/static/js/csentry.js
+++ b/app/static/js/csentry.js
@@ -71,7 +71,12 @@ function update_selectfield(field_id, data, selected_value) {
     }
     $field.append($("<option></option>").attr("value", option).text(text));
   });
-  $field.val(selected_value);
+  if( selected_value == "" ) {
+    $field.prop("disabled", true);
+  } else {
+    $field.val(selected_value);
+    $field.prop("disabled", false);
+  }
 }
 
 // Function to populate dynamically the stack_member field
diff --git a/migrations/versions/33720bfb353a_allow_null_vlan_id.py b/migrations/versions/33720bfb353a_allow_null_vlan_id.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2a736527b00d99e5673084c915a45539e2b1c7a
--- /dev/null
+++ b/migrations/versions/33720bfb353a_allow_null_vlan_id.py
@@ -0,0 +1,36 @@
+"""Allow null vlan id
+
+Revision ID: 33720bfb353a
+Revises: cb777d44627f
+Create Date: 2019-06-10 17:03:44.867111
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = "33720bfb353a"
+down_revision = "cb777d44627f"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.alter_column("network", "vlan_id", existing_type=sa.INTEGER(), nullable=True)
+    op.alter_column(
+        "network_scope", "first_vlan", existing_type=sa.INTEGER(), nullable=True
+    )
+    op.alter_column(
+        "network_scope", "last_vlan", existing_type=sa.INTEGER(), nullable=True
+    )
+
+
+def downgrade():
+    op.alter_column(
+        "network_scope", "last_vlan", existing_type=sa.INTEGER(), nullable=False
+    )
+    op.alter_column(
+        "network_scope", "first_vlan", existing_type=sa.INTEGER(), nullable=False
+    )
+    op.alter_column("network", "vlan_id", existing_type=sa.INTEGER(), nullable=False)
diff --git a/tests/functional/test_web.py b/tests/functional/test_web.py
index bf7f787e6cf09cff6fb2a824142e11705503cdb4..5907be5d9a318f7de209ca7650b331ffe8dca9f1 100644
--- a/tests/functional/test_web.py
+++ b/tests/functional/test_web.py
@@ -542,3 +542,113 @@ def test_delete_host_as_normal_user(logged_rw_client, host_factory, user_factory
     )
     assert response.status_code == 403
     assert len(models.Host.query.all()) == 1
+
+
+def test_create_network_scope(logged_admin_client, domain_factory):
+    domain = domain_factory(name="prod.example.org")
+    name = "MyNetworks"
+    first_vlan = 200
+    last_vlan = 300
+    supernet = "192.168.0.0/16"
+    form = {
+        "name": name,
+        "first_vlan": first_vlan,
+        "last_vlan": last_vlan,
+        "supernet": supernet,
+        "domain_id": domain.id,
+    }
+    response = logged_admin_client.post("/network/scopes/create", data=form)
+    assert response.status_code == 302
+    # The network scope was created
+    scope = models.NetworkScope.query.filter_by(name=name).first()
+    assert scope is not None
+    assert scope.name == name
+    assert scope.first_vlan == first_vlan
+    assert scope.last_vlan == last_vlan
+    assert scope.supernet == supernet
+
+
+def test_create_network_scope_no_vlan(logged_admin_client, domain_factory):
+    domain = domain_factory(name="lab.example.org")
+    name = "NoVlan"
+    supernet = "192.168.0.0/16"
+    form = {
+        "name": name,
+        "first_vlan": "",
+        "last_vlan": None,
+        "supernet": supernet,
+        "domain_id": domain.id,
+    }
+    response = logged_admin_client.post("/network/scopes/create", data=form)
+    assert response.status_code == 302
+    # The network scope was created
+    scope = models.NetworkScope.query.filter_by(name=name).first()
+    assert scope is not None
+    assert scope.name == name
+    assert scope.first_vlan is None
+    assert scope.last_vlan is None
+    assert scope.supernet == supernet
+
+
+def test_create_network(logged_admin_client, domain_factory, network_scope_factory):
+    domain = domain_factory(name="lab.example.org")
+    scope = network_scope_factory(
+        name="MyNetworks",
+        first_vlan=100,
+        last_vlan=200,
+        supernet="192.168.0.0/16",
+        domain_id=domain.id,
+    )
+    vlan_name = "my-network"
+    form = {
+        "scope_id": scope.id,
+        "vlan_name": vlan_name,
+        "vlan_id": 101,
+        "address": "192.168.0.0/24",
+        "first_ip": "192.168.0.11",
+        "last_ip": "192.168.0.249",
+        "gateway": "192.168.0.254",
+        "domain_id": domain.id,
+        "admin_only": False,
+    }
+    response = logged_admin_client.post("/network/networks/create", data=form)
+    assert response.status_code == 302
+    # The network was created
+    network = models.Network.query.filter_by(vlan_name=vlan_name).first()
+    assert network is not None
+    assert network.vlan_name == vlan_name
+    assert network.address == form["address"]
+    assert network.vlan_id == form["vlan_id"]
+
+
+def test_create_network_no_vlan(
+    logged_admin_client, domain_factory, network_scope_factory
+):
+    domain = domain_factory(name="lab.example.org")
+    scope = network_scope_factory(
+        name="NoVlanNetworks",
+        first_vlan=None,
+        last_vlan=None,
+        supernet="192.168.0.0/16",
+        domain_id=domain.id,
+    )
+    vlan_name = "my-network"
+    form = {
+        "scope_id": scope.id,
+        "vlan_name": vlan_name,
+        "vlan_id": "",
+        "address": "192.168.0.0/24",
+        "first_ip": "192.168.0.11",
+        "last_ip": "192.168.0.249",
+        "gateway": "192.168.0.254",
+        "domain_id": domain.id,
+        "admin_only": False,
+    }
+    response = logged_admin_client.post("/network/networks/create", data=form)
+    assert response.status_code == 302
+    # The network was created
+    network = models.Network.query.filter_by(vlan_name=vlan_name).first()
+    assert network is not None
+    assert network.vlan_name == vlan_name
+    assert network.address == form["address"]
+    assert network.vlan_id is None