diff --git a/Base/Geometry/Reader/imstkMeshIO.cpp b/Base/Geometry/Reader/imstkMeshIO.cpp
index 28d106ed2a6e438aa6beb0c07f898ee8a7ee9316..9415fc9948788762494abba38971d65012c8a1f1 100644
--- a/Base/Geometry/Reader/imstkMeshIO.cpp
+++ b/Base/Geometry/Reader/imstkMeshIO.cpp
@@ -149,6 +149,12 @@ MeshIO::write(const std::shared_ptr<imstk::Mesh> imstkMesh, const std::string& f
         case MeshFileType::VEG:
             return VegaMeshIO::write(imstkMesh, filePath, meshType);
             break;
+        case MeshFileType::VTU:
+        case MeshFileType::VTP:
+        case MeshFileType::STL:
+        case MeshFileType::PLY:
+            return VTKMeshIO::write(imstkMesh, filePath, meshType);
+            break;
     }
 
     LOG(WARNING) << "MeshIO::write error: file type not supported";
diff --git a/Base/Geometry/Reader/imstkVTKMeshIO.cpp b/Base/Geometry/Reader/imstkVTKMeshIO.cpp
index 2b1c4cdd376d1d5faedd27737f87117d586569e5..508a348faefd63dacbe99c18d33d55a57f942cef 100644
--- a/Base/Geometry/Reader/imstkVTKMeshIO.cpp
+++ b/Base/Geometry/Reader/imstkVTKMeshIO.cpp
@@ -28,6 +28,10 @@
 #include "vtkPLYReader.h"
 #include "vtkOBJReader.h"
 #include "vtkSTLReader.h"
+#include "vtkUnstructuredGridWriter.h"
+#include "vtkXMLPolyDataWriter.h"
+#include "vtkPLYWriter.h"
+#include "vtkSTLWriter.h"
 #include "vtkFloatArray.h"
 #include "vtkTriangleFilter.h"
 
@@ -44,42 +48,71 @@ VTKMeshIO::read(const std::string& filePath, MeshFileType meshType)
     case MeshFileType::VTK :
     {
         return VTKMeshIO::readVtkGenericFormatData<vtkGenericDataObjectReader>(filePath);
-        break;
     }
     case MeshFileType::VTU :
     {
         return VTKMeshIO::readVtkUnstructuredGrid<vtkXMLUnstructuredGridReader>(filePath);
-        break;
     }
     case MeshFileType::VTP :
     {
         return VTKMeshIO::readVtkPolyData<vtkXMLPolyDataReader>(filePath);
-        break;
     }
     case MeshFileType::STL :
     {
         return VTKMeshIO::readVtkPolyData<vtkSTLReader>(filePath);
-        break;
     }
     case MeshFileType::PLY :
     {
         return VTKMeshIO::readVtkPolyData<vtkPLYReader>(filePath);
-        break;
     }
     case MeshFileType::OBJ :
     {
         return VTKMeshIO::readVtkPolyData<vtkOBJReader>(filePath);
-        break;
     }
     default :
     {
         LOG(WARNING) << "VTKMeshIO::read error: file type not supported";
         return nullptr;
-        break;
     }
     }
 }
 
+bool
+VTKMeshIO::write(const std::shared_ptr<Mesh> imstkMesh, const std::string & filePath, const MeshFileType meshType)
+{
+    if (auto vMesh = std::dynamic_pointer_cast<VolumetricMesh>(imstkMesh))
+    {
+        switch (meshType)
+        {
+        case MeshFileType::VTU:
+            return VTKMeshIO::writeVtkUnstructuredGrid(vMesh, filePath);
+        default:
+            LOG(WARNING) << "VTKMeshIO::write error: file type not supported for volumetric mesh.";
+            return false;
+        }
+    }
+    else if (auto sMesh = std::dynamic_pointer_cast<SurfaceMesh>(imstkMesh))
+    {
+        switch (meshType)
+        {
+        case MeshFileType::VTP:
+            return VTKMeshIO::writeVtkPolyData<vtkXMLPolyDataWriter>(sMesh, filePath);
+        case MeshFileType::STL:
+            return VTKMeshIO::writeVtkPolyData<vtkSTLWriter>(sMesh, filePath);
+        case MeshFileType::PLY:
+            return VTKMeshIO::writeVtkPolyData<vtkPLYWriter>(sMesh, filePath);
+        default:
+            LOG(WARNING) << "VTKMeshIO::write error: file type not supported for surface mesh.";
+            return false;
+        }
+    }
+    else
+    {
+        LOG(WARNING) << "VTKMeshIO::write error: the provided mesh is not a surface or volumetric mesh.";
+        return false;
+    }
+}
+
 template<typename ReaderType>
 std::shared_ptr<Mesh>
 VTKMeshIO::readVtkGenericFormatData(const std::string& filePath)
@@ -119,6 +152,25 @@ VTKMeshIO::readVtkPolyData(const std::string& filePath)
     return VTKMeshIO::convertVtkPolyDataToSurfaceMesh(vtkMesh);
 }
 
+template<typename WriterType>
+bool
+VTKMeshIO::writeVtkPolyData(const std::shared_ptr<SurfaceMesh> imstkMesh, const std::string & filePath)
+{
+    vtkPolyData* vtkMesh = convertSurfaceMeshToVtkPolyData(imstkMesh);
+    if (!vtkMesh) //conversion unsuccessful
+    {
+        return false;
+    }
+
+    auto writer = vtkSmartPointer<WriterType>::New();
+    writer->SetInputData(vtkMesh);
+    writer->SetFileName(filePath.c_str());
+    writer->Update();
+    vtkMesh->Delete();
+
+    return true;
+}
+
 template<typename ReaderType>
 std::shared_ptr<VolumetricMesh>
 VTKMeshIO::readVtkUnstructuredGrid(const std::string& filePath)
@@ -131,6 +183,41 @@ VTKMeshIO::readVtkUnstructuredGrid(const std::string& filePath)
     return VTKMeshIO::convertVtkUnstructuredGridToVolumetricMesh(vtkMesh);
 }
 
+bool
+VTKMeshIO::writeVtkUnstructuredGrid(const std::shared_ptr<VolumetricMesh> imstkMesh, const std::string & filePath)
+{
+    auto tMesh = std::dynamic_pointer_cast<TetrahedralMesh>(imstkMesh);
+    auto hMesh = std::dynamic_pointer_cast<HexahedralMesh>(imstkMesh);
+    vtkUnstructuredGrid* vtkMesh = nullptr;
+    if (tMesh)
+    {
+        vtkMesh = convertTetrahedralMeshToVtkUnstructuredGrid(tMesh);
+    }
+    else if (hMesh)
+    {
+        vtkMesh = convertHexahedralMeshToVtkUnstructuredGrid(hMesh);
+    }
+    else
+    {
+        LOG(WARNING) << "VTKMeshIO::writeVtkUnstructuredGrid error: mesh is neither tetrahedral nor hexahedral";
+        return false;
+    }
+
+    if (!vtkMesh)
+    {
+        LOG(WARNING) << "VTKMeshIO::writeVtkUnstructuredGrid error: conversion unsuccessful";
+        return false;
+    }
+
+    auto writer = vtkSmartPointer<vtkUnstructuredGridWriter>::New();
+    writer->SetInputData(vtkMesh);
+    writer->SetFileName(filePath.c_str());
+    writer->Update();
+    vtkMesh->Delete();
+
+    return true;
+}
+
 std::shared_ptr<SurfaceMesh>
 VTKMeshIO::convertVtkPolyDataToSurfaceMesh(vtkPolyData* vtkMesh)
 {
@@ -141,10 +228,10 @@ VTKMeshIO::convertVtkPolyDataToSurfaceMesh(vtkPolyData* vtkMesh)
     }
 
     StdVectorOfVec3d vertices;
-    VTKMeshIO::copyVertices(vtkMesh->GetPoints(), vertices);
+    VTKMeshIO::copyVerticesFromVtk(vtkMesh->GetPoints(), vertices);
 
     std::vector<SurfaceMesh::TriangleArray> triangles;
-    VTKMeshIO::copyCells<3>(vtkMesh->GetPolys(), triangles);
+    VTKMeshIO::copyCellsFromVtk<3>(vtkMesh->GetPolys(), triangles);
 
     auto mesh = std::make_shared<SurfaceMesh>();
     mesh->initialize(vertices, triangles, true);
@@ -167,6 +254,51 @@ VTKMeshIO::convertVtkPolyDataToSurfaceMesh(vtkPolyData* vtkMesh)
     return mesh;
 }
 
+vtkPolyData*
+VTKMeshIO::convertSurfaceMeshToVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh)
+{
+    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
+    VTKMeshIO::copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
+
+    vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
+    VTKMeshIO::copyCellsToVtk<3>(imstkMesh->getTrianglesVertices(), polys.Get());
+
+    vtkPolyData *polydata = vtkPolyData::New();
+    polydata->SetPoints(points);
+    polydata->SetPolys(polys);
+    return polydata;
+}
+
+vtkUnstructuredGrid*
+VTKMeshIO::convertTetrahedralMeshToVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> imstkMesh)
+{
+    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
+    VTKMeshIO::copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
+
+    vtkSmartPointer<vtkCellArray> tetras = vtkSmartPointer<vtkCellArray>::New();
+    VTKMeshIO::copyCellsToVtk<4>(imstkMesh->getTetrahedraVertices(), tetras.Get());
+
+    vtkUnstructuredGrid *ug = vtkUnstructuredGrid::New();
+    ug->SetPoints(points);
+    ug->SetCells(VTK_TETRA, tetras);
+    return ug;
+}
+
+vtkUnstructuredGrid*
+VTKMeshIO::convertHexahedralMeshToVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> imstkMesh)
+{
+    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
+    VTKMeshIO::copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
+
+    vtkSmartPointer<vtkCellArray> bricks = vtkSmartPointer<vtkCellArray>::New();
+    VTKMeshIO::copyCellsToVtk<8>(imstkMesh->getHexahedraVertices(), bricks.Get());
+
+    vtkUnstructuredGrid *ug = vtkUnstructuredGrid::New();
+    ug->SetPoints(points);
+    ug->SetCells(VTK_HEXAHEDRON, bricks);
+    return ug;
+}
+
 std::shared_ptr<VolumetricMesh>
 VTKMeshIO::convertVtkUnstructuredGridToVolumetricMesh(vtkUnstructuredGrid* vtkMesh)
 {
@@ -177,13 +309,13 @@ VTKMeshIO::convertVtkUnstructuredGridToVolumetricMesh(vtkUnstructuredGrid* vtkMe
     }
 
     StdVectorOfVec3d vertices;
-    VTKMeshIO::copyVertices(vtkMesh->GetPoints(), vertices);
+    VTKMeshIO::copyVerticesFromVtk(vtkMesh->GetPoints(), vertices);
 
     int cellType = vtkMesh->GetCellType(vtkMesh->GetNumberOfCells()-1);
     if( cellType == VTK_TETRA )
     {
         std::vector<TetrahedralMesh::TetraArray> cells;
-        VTKMeshIO::copyCells<4>(vtkMesh->GetCells(), cells);
+        VTKMeshIO::copyCellsFromVtk<4>(vtkMesh->GetCells(), cells);
 
         auto mesh = std::make_shared<TetrahedralMesh>();
         mesh->initialize(vertices, cells, false);
@@ -192,7 +324,7 @@ VTKMeshIO::convertVtkUnstructuredGridToVolumetricMesh(vtkUnstructuredGrid* vtkMe
     else if( cellType == VTK_HEXAHEDRON )
     {
         std::vector<HexahedralMesh::HexaArray> cells;
-        VTKMeshIO::copyCells<8>(vtkMesh->GetCells(), cells);
+        VTKMeshIO::copyCellsFromVtk<8>(vtkMesh->GetCells(), cells);
 
         auto mesh = std::make_shared<HexahedralMesh>();
         mesh->initialize(vertices, cells, false);
@@ -207,14 +339,15 @@ VTKMeshIO::convertVtkUnstructuredGridToVolumetricMesh(vtkUnstructuredGrid* vtkMe
 }
 
 void
-VTKMeshIO::copyVertices(vtkPoints* points, StdVectorOfVec3d& vertices)
+VTKMeshIO::copyVerticesFromVtk(vtkPoints* points, StdVectorOfVec3d& vertices)
 {
     if(!points)
     {
-        LOG(WARNING) << "VTKMeshIO::copyVertices error: No points found.";
+        LOG(WARNING) << "VTKMeshIO::copyVerticesFromVtk error: No points found.";
         return;
     }
 
+    vertices.reserve(points->GetNumberOfPoints());
     for(vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i)
     {
         double pos[3];
@@ -223,16 +356,52 @@ VTKMeshIO::copyVertices(vtkPoints* points, StdVectorOfVec3d& vertices)
     }
 }
 
+void VTKMeshIO::copyVerticesToVtk(const StdVectorOfVec3d & vertices, vtkPoints * points)
+{
+    if (!points)
+    {
+        LOG(WARNING) << "VTKMeshIO::copyVerticesToVtk error: No points found.";
+        return;
+    }
+
+    points->SetNumberOfPoints(vertices.size());
+    for (size_t i = 0; i < vertices.size(); i++)
+    {
+        points->SetPoint(i, vertices[i][0], vertices[i][1], vertices[i][2]);
+    }
+}
+
+template<size_t dim>
+void VTKMeshIO::copyCellsToVtk(const std::vector<std::array<size_t, dim>>& cells, vtkCellArray * vtkCells)
+{
+    if (!vtkCells)
+    {
+        LOG(WARNING) << "VTKMeshIO::copyCellsToVtk error: No cells found.";
+        return;
+    }
+
+    for (size_t i = 0; i < cells.size(); i++)
+    {
+
+        vtkCells->InsertNextCell(dim);
+        for (size_t k = 0; k < dim; k++)
+        {
+            vtkCells->InsertCellPoint(cells[i][k]);
+        }
+    }
+}
+
 template<size_t dim>
 void
-VTKMeshIO::copyCells(vtkCellArray* vtkCells, std::vector<std::array<size_t,dim>>& cells)
+VTKMeshIO::copyCellsFromVtk(vtkCellArray* vtkCells, std::vector<std::array<size_t,dim>>& cells)
 {
     if(!vtkCells)
     {
-        LOG(WARNING) << "VTKMeshIO::copyCells error: No cells found.";
+        LOG(WARNING) << "VTKMeshIO::copyCellsFromVtk error: No cells found.";
         return;
     }
 
+    cells.reserve(vtkCells->GetNumberOfCells());
     vtkCells->InitTraversal();
     auto vtkCell = vtkSmartPointer<vtkIdList>::New();
     std::array<size_t, dim> cell;
@@ -258,19 +427,19 @@ VTKMeshIO::copyPointData(vtkPointData* pointData, std::map<std::string, StdVecto
         return;
     }
 
-    for (unsigned int i = 0; i < pointData->GetNumberOfArrays(); ++i)
+    for (int i = 0; i < pointData->GetNumberOfArrays(); ++i)
     {
         vtkDataArray* array = pointData->GetArray(i);
         std::string name = array->GetName();
         int nbrOfComp = array->GetNumberOfComponents();
-        int nbrOfTuples = array->GetNumberOfTuples();
+        vtkIdType nbrOfTuples = array->GetNumberOfTuples();
         StdVectorOfVectorf data;
-        for(unsigned int j = 0; j < nbrOfTuples; ++j)
+        for(vtkIdType j = 0; j < nbrOfTuples; ++j)
         {
             double* tupleData = new double [nbrOfComp];
             array->GetTuple(j, tupleData);
             Vectorf tuple(nbrOfComp);
-            for (unsigned int k = 0; k < nbrOfComp; k++)
+            for (int k = 0; k < nbrOfComp; k++)
               {
               tuple[k] = tupleData[k];
               }
diff --git a/Base/Geometry/Reader/imstkVTKMeshIO.h b/Base/Geometry/Reader/imstkVTKMeshIO.h
index 0ca2f6d7d4a67425def246417c534a49d9fb7a70..ca0f0d5469976caa9283c41fe01a1a8f0815d4d0 100644
--- a/Base/Geometry/Reader/imstkVTKMeshIO.h
+++ b/Base/Geometry/Reader/imstkVTKMeshIO.h
@@ -62,6 +62,11 @@ public:
     ///
     static std::shared_ptr<Mesh> read(const std::string& filePath, MeshFileType meshType);
 
+    ///
+    /// \brief Writes the given mesh to the specified file path.
+    ///
+    static bool write(const std::shared_ptr<Mesh> imstkMesh, const std::string& filePath, const MeshFileType meshType);
+
 protected:
 
     ///
@@ -76,6 +81,17 @@ protected:
     template<typename ReaderType>
     static std::shared_ptr<SurfaceMesh> readVtkPolyData(const std::string& filePath);
 
+    ///
+    /// \brief Writes the given surfase mesh to given file path using the provided writer type
+    ///
+    template<typename WriterType>
+    static bool writeVtkPolyData(const std::shared_ptr<SurfaceMesh> imstkMesh, const std::string& filePath);
+
+    ///
+    /// \brief Writes the given volumetric mesh to given file path
+    ///
+    static bool writeVtkUnstructuredGrid(const std::shared_ptr<VolumetricMesh> imstkMesh, const std::string& filePath);
+
     ///
     /// \brief
     ///
@@ -87,6 +103,21 @@ protected:
     ///
     static std::shared_ptr<SurfaceMesh> convertVtkPolyDataToSurfaceMesh(vtkPolyData* vtkMesh);
 
+    ///
+    /// \brief Converts imstk surface mesh into a vtk polydata suitable for writing to file
+    ///
+    static vtkPolyData* convertSurfaceMeshToVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh);
+
+    ///
+    /// \brief Converts imstk tetrahedral mesh into a vtk unstructured grid suitable for writing to file
+    ///
+    static vtkUnstructuredGrid* convertTetrahedralMeshToVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> imstkMesh);
+
+    ///
+    /// \brief Converts imstk hexahedral mesh into a vtk unstructured grid suitable for writing to file
+    ///
+    static vtkUnstructuredGrid * convertHexahedralMeshToVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> imstkMesh);
+
     ///
     /// \brief
     ///
@@ -95,13 +126,24 @@ protected:
     ///
     /// \brief
     ///
-    static void copyVertices(vtkPoints* points, StdVectorOfVec3d& vertices);
+    static void copyVerticesFromVtk(vtkPoints* points, StdVectorOfVec3d& vertices);
+
+    ///
+    /// \brief Copies vertices from imstk structure to VTK one
+    ///
+    static void copyVerticesToVtk(const StdVectorOfVec3d& vertices, vtkPoints* points);
+
+    ///
+    /// \brief Copies cells of the given dimension from imstk structure to VTK one
+    ///
+    template<size_t dim>
+    static void copyCellsToVtk(const std::vector<std::array<size_t, dim>>& cells, vtkCellArray* vtkCells);
 
     ///
     /// \brief
     ///
     template<size_t dim>
-    static void copyCells(vtkCellArray* vtkCells, std::vector<std::array<size_t,dim>>& cells);
+    static void copyCellsFromVtk(vtkCellArray* vtkCells, std::vector<std::array<size_t,dim>>& cells);
 
     ///
     /// \brief