diff --git a/.eslintrc.json b/.eslintrc.json
index e2dc1f64c88e0cb98b1e16c50537c4926d1db9ac..c6f6bd66111e059840ad9df3853d7cacb8b35eea 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,3 +1,6 @@
 {
-	"extends": "@bark"
+	"extends": "@bark",
+	"parserOptions": {
+		"ecmaVersion": 8
+	}
 }
\ No newline at end of file
diff --git a/index.js b/index.js
index a0bffd9b38c559fbe8c060a46ec289f5fb727581..930c038a5aa359e12b68062539344b2bd24fc4b2 100644
--- a/index.js
+++ b/index.js
@@ -1,3 +1,89 @@
-module.exports = function createMustacheMiddleware(viewDir) {
-	
+const path = require('path')
+const fs = require('fs-jetpack')
+const Mustache = require('mustache')
+
+function createPathsFromContext(context = '', filename) {
+	const { name } = path.parse(filename)
+	return [
+		path.join(context, filename),
+		path.join(context, name),
+	]
+}
+
+function createFileMap(dir, root, ext, debug) {
+	const cache = {}
+	const tree = dir.inspectTree(root)
+	if (tree.type !== 'dir') {
+		throw new TypeError(`[koa-mustache] viewDir must be an actual directory, found ${ tree.type }`)
+	}
+
+	const processing = tree.children
+	while (processing.length > 0) {
+		const current = processing.shift()
+
+		if (current.type === 'dir') {
+			for (const child of current.children) {
+				child.context = current.context ? path.join(current.context, current.name) : current.name
+				processing.push(child)
+			}
+		} else if (current.type === 'file') {
+			if (path.extname(current.name) === ext) {
+				const [pathWithExt, pathWithoutExt] = createPathsFromContext(current.context, current.name)
+				const content = dir.read(dir.path(root, pathWithExt), 'utf8')
+
+				debug(`[koa-mustache] Loading file ${ pathWithExt }`)
+
+				Mustache.parse(content)
+				cache[pathWithExt] = content
+				cache[pathWithoutExt] = content
+			}
+		}
+	}
+	return cache
+}
+
+module.exports = function createMustacheMiddleware(viewDir, opts = {}) {
+	const useCache = opts.hasOwnProperty('cache') ? opts.cache : process.env.NODE_ENV === 'production'
+	const extension = opts.hasOwnProperty('extension') ? opts.extension : '.mustache'
+	const partialDir = opts.hasOwnProperty('partials') ? opts.partials : 'partials'
+	const debug = opts.debug || (() => {}) // eslint-disable-line no-empty-function
+
+	const viewRoot = fs.cwd(viewDir)
+
+	const cache = useCache ? createFileMap(viewRoot, '.', extension, debug) : {}
+	const partials = createFileMap(viewRoot, partialDir, extension, debug)
+
+	return function attachRenderFunc(ctx, next) {
+		ctx.render = async function renderTemplateData(template, data = {}) {
+			if (useCache) {
+				const templateContent = cache[template]
+				if (templateContent == null) {
+					this.status = 404
+				} else {
+					this.status = 200
+					this.body = Mustache.render(templateContent, data, partials)
+				}
+			} else {
+				let fileData = await viewRoot.inspectAsync(template)
+				if (fileData == null) {
+					template += extension
+					fileData = await viewRoot.inspectAsync(template)
+					if (fileData == null) {
+						this.status = 404
+						return
+					}
+				}
+
+				if (fileData.type === 'file') {
+					const contents = await viewRoot.readAsync(template, 'utf8')
+					this.status = 200
+					this.body = Mustache.render(contents, data, partials)
+				} else {
+					this.status = 500
+				}
+			}
+		}.bind(ctx)
+
+		return next()
+	}
 }
diff --git a/package-lock.json b/package-lock.json
index 2b5f9527049d71c975695b9b00ed0026a63aaf48..2e0f9162ea5b4a4c6ad6ef2f82eac66dc1e425af 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -137,14 +137,12 @@
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-      "dev": true
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
     },
     "brace-expansion": {
       "version": "1.1.8",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
       "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
-      "dev": true,
       "requires": {
         "balanced-match": "1.0.0",
         "concat-map": "0.0.1"
@@ -247,8 +245,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "concat-stream": {
       "version": "1.6.0",
@@ -491,6 +488,14 @@
         "write": "0.2.1"
       }
     },
+    "fs-jetpack": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-1.2.0.tgz",
+      "integrity": "sha512-wEncEDStClGlHrQvqClINppjLdjQMcy3UFhu4DKrbTCIQHmiC+7r3nNvnc+3aiHxHaPfWXdA8UdCHNHGLJKciA==",
+      "requires": {
+        "minimatch": "3.0.4"
+      }
+    },
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -732,7 +737,6 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
       "requires": {
         "brace-expansion": "1.1.8"
       }
@@ -758,6 +762,11 @@
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
       "dev": true
     },
+    "mustache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz",
+      "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA="
+    },
     "mute-stream": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
diff --git a/package.json b/package.json
index ed88a1839b9f329b9af231603b7d4af4279bf8f3..10de4610890bcdb9f6f1382962f9d1a18123789a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@commander-lol/koa-mustache",
-  "version": "1.0.0",
+  "version": "1.0.1-beta1",
   "description": "Mustache rendering for Koa 2+",
   "main": "index.js",
   "scripts": {
@@ -18,5 +18,9 @@
   "devDependencies": {
     "@bark/eslint-config": "^0.1.2",
     "eslint": "^4.16.0"
+  },
+  "dependencies": {
+    "fs-jetpack": "^1.2.0",
+    "mustache": "^2.3.0"
   }
 }