diff --git a/Applications/CLI/ogs.cpp b/Applications/CLI/ogs.cpp
index 1b502e02e5178582be190eafa40ecf74bd066b44..0551cc5e432ec833b84803838f41dfc6842cd3f9 100644
--- a/Applications/CLI/ogs.cpp
+++ b/Applications/CLI/ogs.cpp
@@ -25,7 +25,7 @@
 
 #include "ProcessLib/NumericsConfig.h"
 
-void solveProcesses(ProjectData &project)
+void solveProcesses(ProjectData &project, const std::string &outdir)
 {
 	INFO("Solve processes.");
 
@@ -58,8 +58,9 @@ void solveProcesses(ProjectData &project)
 			}
 
 			std::string const output_file_name =
-			    out_pref + "_pcs_" + std::to_string(i) + "_ts_" +
-			    std::to_string(timestep) + ".vtu";
+				BaseLib::joinPaths(outdir, out_pref) +
+				"_pcs_" + std::to_string(i) + "_ts_" +
+				std::to_string(timestep) + ".vtu";
 			(*p)->postTimestep(output_file_name, timestep);
 
 			++i;
@@ -90,6 +91,14 @@ int main(int argc, char *argv[])
 		"PROJECT FILE");
 	cmd.add(project_arg);
 
+	TCLAP::ValueArg<std::string> outdir_arg(
+		"o", "output-directory",
+		"the output directory to write to",
+		false,
+		"",
+		"output directory");
+	cmd.add(outdir_arg);
+
 	TCLAP::SwitchArg nonfatal_arg("",
 		"config-warnings-nonfatal",
 		"warnings from parsing the configuration file will not trigger program abortion");
@@ -117,9 +126,8 @@ int main(int argc, char *argv[])
 		(*p_it)->initialize();
 	}
 
-	std::string const output_file_name(project.getOutputFilePrefix() + ".vtu");
 
-	solveProcesses(project);
+	solveProcesses(project, outdir_arg.getValue());
 
 	return 0;
 }
diff --git a/BaseLib/FileTools.cpp b/BaseLib/FileTools.cpp
index b7a8cb3b7faf8be79f596dfd83ba99fef6b89a78..4bdb248ad23a01397879fb2ff697b23dc67dfbce 100644
--- a/BaseLib/FileTools.cpp
+++ b/BaseLib/FileTools.cpp
@@ -133,4 +133,28 @@ std::string extractPath(std::string const& pathname)
 	const std::size_t pos = findLastPathSeparator(pathname);
 	return pathname.substr(0, pos + 1);
 }
+const char * pathSeparator =
+#ifdef _WIN32
+                            "\\";
+#else
+                            "/";
+#endif
+
+std::string appendPathSeparator(std::string const& path)
+{
+	if(findLastPathSeparator(path) == path.length() - 1)
+		return path;
+	return path + pathSeparator;
+}
+
+std::string joinPaths(std::string const& pathA, std::string const& pathB)
+{
+	std::string tmpB(pathB);
+	if(tmpB.substr(0, 1) == ".")
+		tmpB = tmpB.substr(1);
+	if(tmpB.substr(0, 1) == pathSeparator)
+		tmpB = tmpB.substr(1);
+	return appendPathSeparator(pathA) + tmpB;
+}
+
 } // end namespace BaseLib
diff --git a/BaseLib/FileTools.h b/BaseLib/FileTools.h
index d3e17dcdf10e4f8e2bc4a3a485b4970e3f54518e..a24f8aa25629668dbc78677e67940bb749ca52b5 100644
--- a/BaseLib/FileTools.h
+++ b/BaseLib/FileTools.h
@@ -152,6 +152,17 @@ std::string copyPathToFileName(const std::string &file_name,
  * Returns a string up to the last path separator not including it.
  */
 std::string extractPath(std::string const& pathname);
+
+/**
+ * Appends a platform-dependent path separator (/ or \) if missing
+ */
+std::string appendPathSeparator(std::string const& path);
+
+/**
+ * Concat two paths. Does not check for validity.
+ */
+std::string joinPaths(std::string const& pathA, std::string const& pathB);
+
 } // end namespace BaseLib
 
 #endif // FILETOOLS_H
diff --git a/ProcessLib/Process.h b/ProcessLib/Process.h
index ae2c5a9f490a61492d0c9d469d1984c1bc7ec968..ce7c9abcbc2323f1695de488991b9ea44790f892 100644
--- a/ProcessLib/Process.h
+++ b/ProcessLib/Process.h
@@ -278,6 +278,7 @@ private:
 #endif
 
 		// Write output file
+		DBUG("Writing output to \'%s\'.", file_name.c_str());
 		FileIO::VtuInterface vtu_interface(&_mesh, vtkXMLWriter::Binary, true);
 		vtu_interface.writeToFile(file_name);
 	}
diff --git a/Tests/BaseLib/TestFilePathStringManipulation.cpp b/Tests/BaseLib/TestFilePathStringManipulation.cpp
index fecceb7d962ef96aa9e3a8b55d0ce916d16cd606..404071db495ce3eba6ed890801151783f52da995 100644
--- a/Tests/BaseLib/TestFilePathStringManipulation.cpp
+++ b/Tests/BaseLib/TestFilePathStringManipulation.cpp
@@ -387,3 +387,16 @@ TEST(BaseLib, ExtractPathUnix)
 	ASSERT_EQ ( BaseLib::extractPath("/path/path/file.ext"), "/path/path/" );
 	ASSERT_EQ ( BaseLib::extractPath("/path/path/path.ext/"), "/path/path/path.ext/" );
 }
+
+TEST(BaseLib, JoinPaths)
+{
+#if _WIN32
+	ASSERT_EQ ( "\\path\\path", BaseLib::joinPaths("\\path", "path") );
+	ASSERT_EQ ( "\\path\\path", BaseLib::joinPaths("\\path", "\\path") );
+	ASSERT_EQ ( "\\path\\path", BaseLib::joinPaths("\\path", ".\\path") );
+#else
+	ASSERT_EQ ( "/path/path", BaseLib::joinPaths("/path", "path") );
+	ASSERT_EQ ( "/path/path", BaseLib::joinPaths("/path", "/path") );
+	ASSERT_EQ ( "/path/path", BaseLib::joinPaths("/path", "./path") );
+#endif
+}