diff --git a/projects/frontend/src/utilities/fetch.ts b/projects/frontend/src/utilities/fetch.ts
index 18362a8..6ccb4a6 100644
--- a/projects/frontend/src/utilities/fetch.ts
+++ b/projects/frontend/src/utilities/fetch.ts
@@ -114,15 +114,44 @@ export const fetchAndReturnText = async (path: string) => {
  * @returns the content of the YAML file after sanitizing then parsing
  */
 export const fetchAndParseYaml = async <T>(path: string) => {
+  const text = await fetchAndReturnText(path)
+  return yaml.load(text) as T // do not catch exceptions
+}
+
+/**
+ * Fetches, sanitizes, and parses JSON files
+ * @param path the path of the JSON file to load
+ * @returns the content of the JSON file after sanitizing then parsing
+ */
+export const fetchAndParseJson = async<T>(path: string) => {
+  const text = await fetchAndReturnText(path)
+  return JSON.parse(text) as T // do not catch exceptions
+}
+
+/**
+ * Fetches, sanitizes, and parses a config file;
+ * valid config files are in YAML or JSON
+ * @param path the path of the config file to load
+ * @returns the content of the config file after sanitizing then parsing
+ */
+export const fetchAndParseConfig = async<T>(path: string) => {
   const store = useRouteStore()
   const existing = store.getFile<T>(path)
   if (!!existing) {
     return existing
   } else {
-    const text = await fetchAndReturnText(path)
-    const obj = yaml.load(text) as T
-    store.cacheFile(path, obj)
-    return obj
+    let parsed = {}
+    if (path.endsWith('.yml') || path.endsWith('.yaml')) {
+      parsed = await fetchAndParseYaml(path)
+    } else if (path.endsWith('.json')) {
+      parsed = await fetchAndParseJson(path)
+    } else {
+      // stop execution
+      throw new Error(`Invalid config specified at ${path}`)
+    }
+
+    store.cacheFile(path, parsed)
+    return parsed as T
   }
 }
 
@@ -159,7 +188,7 @@ export const fetchConfigsFromList = async <T>(list: ListWithEntries<T>): Promise
     if (!!list.entries) {
       ids = ids.concat(Object.keys(list.entries))
       ids.forEach(id => {
-        entries[id] = fetchAndParseYaml<T>((list.entries!)[id])
+        entries[id] = fetchAndParseConfig<T>((list.entries!)[id])
       })
     }
     if (!!list.embeddedEntries) {
@@ -187,7 +216,7 @@ export const fetchConfigByIdFromList = async <T>(list: ListWithEntries<T>, id: s
     if (!!list.embeddedEntries && list.embeddedEntries[id]) {
       resolve(list.embeddedEntries[id])
     } else if (!!list.entries && list.entries[id]) {
-      const config = await fetchAndParseYaml<T>(list.entries[id])
+      const config = await fetchAndParseConfig<T>(list.entries[id])
       resolve(config)
     }
   })
diff --git a/projects/frontend/src/views/article/article-view.vue b/projects/frontend/src/views/article/article-view.vue
index 58dbd0f..bc0fc55 100644
--- a/projects/frontend/src/views/article/article-view.vue
+++ b/projects/frontend/src/views/article/article-view.vue
@@ -7,7 +7,7 @@ import type {
   RoutedWindow,
 } from '@goldenwere/mackenzii-types'
 
-import { fetchAndParseMarkdown, fetchAndParseYaml, fetchConfigByIdFromList } from 'src/utilities/fetch'
+import { fetchAndParseMarkdown, fetchAndParseConfig, fetchConfigByIdFromList } from 'src/utilities/fetch'
 import { getCurrentRoute } from 'src/utilities/vuetils'
 import { useRouteStore } from 'src/routes'
 
@@ -28,7 +28,7 @@ const routeConfig = routeStore._routes[currentRoute.path.substring(0, currentRou
 const routeSubConfig = routeStore._routes[currentRoute.path]
 
 onMounted(async () => {
-  const config = await fetchAndParseYaml<ListWithEntries<ArticleEntry>>(routeConfig.config)
+  const config = await fetchAndParseConfig<ListWithEntries<ArticleEntry>>(routeConfig.config)
     resolved.value = await fetchConfigByIdFromList(config, currentRoute.query.id as string)
   const md = await fetchAndParseMarkdown(resolved.value.url)
   content.value = md
diff --git a/projects/frontend/src/views/gallery/gallery-view.vue b/projects/frontend/src/views/gallery/gallery-view.vue
index 49c5989..b72b203 100644
--- a/projects/frontend/src/views/gallery/gallery-view.vue
+++ b/projects/frontend/src/views/gallery/gallery-view.vue
@@ -10,7 +10,7 @@ import type {
   RoutedWindow,
 } from '@goldenwere/mackenzii-types'
 
-import { fetchAndParseYaml, fetchConfigByIdFromList } from 'src/utilities/fetch'
+import { fetchAndParseConfig, fetchConfigByIdFromList } from 'src/utilities/fetch'
 import { getCurrentRoute } from 'src/utilities/vuetils'
 import { useRouteStore } from 'src/routes'
 
@@ -71,7 +71,7 @@ const onButtonClicked = (event: Event | null, direction: number, override?: numb
 }
 
 onMounted(async () => {
-  let config = await fetchAndParseYaml<ListWithEntries<GalleryEntry>>(routeConfig.config)
+  let config = await fetchAndParseConfig<ListWithEntries<GalleryEntry>>(routeConfig.config)
   resolved.value = await fetchConfigByIdFromList(config, currentRoute.query.id as string)
   document.title = routeSubConfig.fullTitle?.replace('$ENTRY', resolved.value.title || currentRoute.query.id as string)
   routeStore.setBreadcrumbs(currentRoute, resolved.value.title || currentRoute.query.id as string)
diff --git a/projects/frontend/src/views/shared/media-list.vue b/projects/frontend/src/views/shared/media-list.vue
index 6d55503..a39d211 100644
--- a/projects/frontend/src/views/shared/media-list.vue
+++ b/projects/frontend/src/views/shared/media-list.vue
@@ -7,7 +7,7 @@ import type {
   MediaEntry,
   ResolvedListEntries,
 } from '@goldenwere/mackenzii-types'
-import { fetchAndParseYaml, fetchConfigsFromList, storage } from 'src/utilities/fetch'
+import { fetchAndParseConfig, fetchConfigsFromList, storage } from 'src/utilities/fetch'
 import { getCurrentRoute } from 'src/utilities/vuetils'
 import { useRouteStore } from 'src/routes'
 
@@ -84,7 +84,7 @@ const onHideWarningsToggled = (event: Event) => {
 }
 
 onMounted(async () => {
-  let listConfig = await fetchAndParseYaml<MediaList>(routeConfig.config)
+  let listConfig = await fetchAndParseConfig<MediaList>(routeConfig.config)
   const list = await fetchConfigsFromList<MediaEntry>(listConfig)
   config.value = listConfig
   entries.value = list.entries