diff --git a/Cargo.lock b/Cargo.lock
index 6777d2e7e4..1a1ab9e19a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1960,6 +1960,7 @@ dependencies = [
  "vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "veloren-client 0.2.0",
  "veloren-common 0.2.0",
+ "veloren-server 0.2.0",
  "winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
diff --git a/voxygen/.gitignore b/voxygen/.gitignore
index 693699042b..4fb75fb34b 100644
--- a/voxygen/.gitignore
+++ b/voxygen/.gitignore
@@ -1,3 +1,4 @@
 /target
 **/*.rs.bk
 Cargo.lock
+settings.toml
diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml
index 0db23602aa..4b9c11fa2b 100644
--- a/voxygen/Cargo.toml
+++ b/voxygen/Cargo.toml
@@ -12,6 +12,7 @@ default = ["gl"]
 [dependencies]
 common = { package = "veloren-common", path = "../common" }
 client = { package = "veloren-client", path = "../client" }
+server = { package = "veloren-server", path = "../server" }
 
 # Graphics
 gfx = "0.17"
diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs
index 7461b53066..a427890201 100644
--- a/voxygen/src/menu/main/mod.rs
+++ b/voxygen/src/menu/main/mod.rs
@@ -1,5 +1,6 @@
 mod client_init;
 mod ui;
+mod singleplayer;
 
 use super::char_selection::CharSelectionState;
 use crate::{
@@ -9,6 +10,7 @@ use crate::{
 use client_init::{ClientInit, Error as InitError};
 use common::{clock::Clock, comp};
 use std::time::Duration;
+use std::thread;
 use ui::{Event as MainMenuEvent, MainMenuUi};
 use vek::*;
 
@@ -100,6 +102,11 @@ impl PlayState for MainMenuState {
                             ),
                         )));
                     }
+                    MainMenuEvent::StartSingleplayer => {
+                        thread::spawn(move || {
+                            singleplayer::run_server();
+                        });
+                    }
                     MainMenuEvent::Quit => return PlayStateResult::Shutdown,
                 }
             }
diff --git a/voxygen/src/menu/main/singleplayer.rs b/voxygen/src/menu/main/singleplayer.rs
new file mode 100644
index 0000000000..93f07030ec
--- /dev/null
+++ b/voxygen/src/menu/main/singleplayer.rs
@@ -0,0 +1,36 @@
+use std::time::Duration;
+use log::info;
+use server::{Input, Event, Server};
+use common::clock::Clock;
+
+const TPS: u64 = 30;
+
+pub fn run_server() {
+    info!("Starting server-cli...");
+
+    // Set up an fps clock
+    let mut clock = Clock::new();
+
+    // Create server
+    let mut server = Server::new()
+        .expect("Failed to create server instance");
+
+    loop {
+        let events = server.tick(Input::default(), clock.get_last_delta())
+            .expect("Failed to tick server");
+
+        for event in events {
+            match event {
+                Event::ClientConnected { entity } => info!("Client connected!"),
+                Event::ClientDisconnected { entity } => info!("Client disconnected!"),
+                Event::Chat { entity, msg } => info!("[Client] {}", msg),
+            }
+        }
+
+        // Clean up the server after a tick
+        server.cleanup();
+
+        // Wait for the next tick
+        clock.tick(Duration::from_millis(1000 / TPS));
+    }
+}
diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs
index c5e7f83504..da2551e0c5 100644
--- a/voxygen/src/menu/main/ui.rs
+++ b/voxygen/src/menu/main/ui.rs
@@ -91,6 +91,7 @@ pub enum Event {
         username: String,
         server_address: String,
     },
+    StartSingleplayer,
     Quit,
 }
 
@@ -172,6 +173,18 @@ impl MainMenuUi {
                 });
             };
         }
+
+        macro_rules! singleplayer {
+            () => {
+                self.login_error = None;
+                events.push(Event::StartSingleplayer);
+                events.push(Event::LoginAttempt {
+                    username: "singleplayer".to_string(),
+                    server_address: "localhost".to_string(),
+                });
+            };
+        }
+
         const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
         // Username
         // TODO: get a lower resolution and cleaner input_bg.png
@@ -296,7 +309,7 @@ impl MainMenuUi {
             .set(self.ids.singleplayer_button, ui_widgets)
             .was_clicked()
         {
-            login!();
+            singleplayer!();
         }
         // Quit
         if Button::image(self.imgs.button)