diff --git a/frontend/.env b/frontend/.env
index ae3abf8f093cb9db6236ce4dd3eb20320ad09cc1..d6e54cd6264755ebdacac63d9fb4ee1f394f476e 100644
--- a/frontend/.env
+++ b/frontend/.env
@@ -1 +1,2 @@
-REACT_APP_API_BASE_URL=/api
\ No newline at end of file
+REACT_APP_API_BASE_URL=/api
+REACT_APP_DEV_ENV=true
\ No newline at end of file
diff --git a/frontend/package.json b/frontend/package.json
index 9851cc8b31f4840455ba469626d78efaee7beff6..35adf2e48db7398e127be8b229208a57ed8a987e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -63,6 +63,7 @@
     "@types/react-dom": "^17.0.9",
     "@types/react-redux": "^7.1.23",
     "@types/redux-persist": "^4.3.1",
-    "@types/yup": "^0.29.13"
+    "@types/yup": "^0.29.13",
+    "redux-devtools-extension": "^2.13.9"
   }
 }
diff --git a/frontend/src/config/conf.ts b/frontend/src/config/conf.ts
index 7c592a317d2799ee429584d951aaaeb2594dc4cb..04125dbb4ee8f380ae971a58dc894d07542ed22c 100644
--- a/frontend/src/config/conf.ts
+++ b/frontend/src/config/conf.ts
@@ -1,5 +1,8 @@
 const conf = {
-    baseUrl: '/api'
+    baseUrl:
+        process.env.REACT_APP_DEV_ENV === 'true'
+            ? 'http://localhost:8080'
+            : '/api',
 }
 
-export default conf;
\ No newline at end of file
+export default conf
diff --git a/frontend/src/features/Catalog/Catalog.tsx b/frontend/src/features/Catalog/Catalog.tsx
index eac9af309b25478ff8fb692b90022d9a0484f5e1..44f1d030e099c8ce1ad168461dd640ae132092f3 100644
--- a/frontend/src/features/Catalog/Catalog.tsx
+++ b/frontend/src/features/Catalog/Catalog.tsx
@@ -1,22 +1,14 @@
 import {
-    Box,
-    Button,
-    Collapse,
     Container,
-    Grid,
     Paper,
-    Stack,
-    TextField,
     Typography,
 } from '@mui/material'
 import CatalogTable from './CatalogTable'
-import { Fragment, useState } from 'react'
+import { Fragment } from 'react'
+import CatalogFilter from './CatalogFilter'
 
 const Catalog = () => {
-    const [filterOpen, setFilterOpen] = useState(false)
-    const toggleFilter = () => {
-        setFilterOpen(!filterOpen)
-    }
+    
 
     return (
         <Fragment>
@@ -27,68 +19,8 @@ const Catalog = () => {
             >
                 <Container sx={{ mt: 4 }}>
                     <Typography variant="h3" sx={{mb: 2}} fontWeight="bold" >Catalog</Typography>
-                    <Button variant="outlined" color="primary" onClick={toggleFilter}>
-                        Filter
-                    </Button>
-                    <Collapse in={filterOpen} timeout="auto" unmountOnExit>
-                        <Grid container spacing={1} alignItems="stretch">
-                            <Grid item xs={6}>
-                                <Stack
-                                    direction="column"
-                                    spacing={1}
-                                    sx={{ mt: 2 }}
-                                >
-                                    <Stack direction="row" spacing={2}>
-                                        <TextField
-                                            size="small"
-                                            id="name"
-                                            label="Name"
-                                        />
-                                        <TextField
-                                            size="small"
-                                            id="type"
-                                            label="Type"
-                                        />
-                                        <TextField
-                                            size="small"
-                                            id="coordinates"
-                                            label="Coordinates"
-                                        />
-                                    </Stack>
-                                    <Stack direction="row" spacing={2}>
-                                        <TextField
-                                            size="small"
-                                            id="writtenForm"
-                                            label="Written form"
-                                        />
-                                        <TextField
-                                            size="small"
-                                            id="stateOrTerritory"
-                                            label="State or territory"
-                                        />
-                                        <TextField
-                                            size="small"
-                                            id="groupBy"
-                                            label="Group by"
-                                        />
-                                    </Stack>
-                                </Stack>
-                            </Grid>
-                            <Grid item xs sx={{ mt: 'auto', ml: 1, mb: 1 }}>
-                                <Stack
-                                    direction="row"
-                                    justifyContent="flex-start"
-                                    alignItems="flex-end"
-                                >
-                                    <Button variant="outlined">Search</Button>
-                                </Stack>
-                            </Grid>
-                        </Grid>
-                    </Collapse>
-
-                    <Box sx={{ mt: 4 }}>
+                        <CatalogFilter />
                         <CatalogTable />
-                    </Box>
                 </Container>
             </Paper>
         </Fragment>
diff --git a/frontend/src/features/Catalog/CatalogFilter.tsx b/frontend/src/features/Catalog/CatalogFilter.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..bbbacc3a5619ecf78d7dee417a0c635e0bde20be
--- /dev/null
+++ b/frontend/src/features/Catalog/CatalogFilter.tsx
@@ -0,0 +1,89 @@
+import { Button, Collapse, Grid, Stack, TextField } from '@mui/material'
+import { Fragment, useState } from 'react'
+import { useDispatch } from 'react-redux'
+import { setFilter, CatalogFilter as Filter } from './catalogSlice'
+import { fetchItems } from './catalogThunks'
+
+const CatalogFilter = () => {
+    const dispatch = useDispatch()
+
+    const [filterOpen, setFilterOpen] = useState(false)
+    const toggleFilter = () => {
+        setFilterOpen(!filterOpen)
+    }
+
+    // current filter object
+    const filter: Filter = {}
+    const applyFilter = () => {
+        dispatch(fetchItems())
+    }
+
+
+    return (
+        <Fragment>
+            <Button variant="outlined" color="primary" onClick={toggleFilter}>
+                Filter
+            </Button>
+            <Collapse in={filterOpen} timeout="auto" unmountOnExit>
+                <Grid container spacing={1} alignItems="stretch">
+                    <Grid item xs={6}>
+                        <Stack direction="column" spacing={1} sx={{ mt: 2 }}>
+                            <Stack direction="row" spacing={2}>
+                                <TextField
+                                    size="small"
+                                    id="name"
+                                    label="Name"
+                                    onChange={(e: any) => { 
+                                        filter.name = e.target.value 
+                                        dispatch(setFilter(filter))
+                                    }}
+                                />
+                                <TextField
+                                    size="small"
+                                    id="type"
+                                    label="Type"
+                                    onChange={(e: any) => {
+                                        filter.type = e.target.value
+                                        dispatch(setFilter(filter))
+                                     }}
+                                />
+                            </Stack>
+                            <Stack direction="row" spacing={2}>
+                                <TextField
+                                    size="small"
+                                    id="writtenForm"
+                                    label="Written form"
+                                />
+                                <TextField
+                                    size="small"
+                                    id="stateOrTerritory"
+                                    label="State or territory"
+                                    onChange={(e: any) => { 
+                                        filter.country = e.target.value 
+                                        dispatch(setFilter(filter))
+                                    }}
+                                />
+                                <TextField
+                                    size="small"
+                                    id="groupBy"
+                                    label="Group by"
+                                />
+                            </Stack>
+                        </Stack>
+                    </Grid>
+                    <Grid item xs sx={{ mt: 'auto', ml: 1, mb: 1 }}>
+                        <Stack
+                            direction="row"
+                            justifyContent="flex-start"
+                            alignItems="flex-end"
+                        >
+                            <Button variant="outlined" onClick={applyFilter}>Search</Button>
+                        </Stack>
+                    </Grid>
+                </Grid>
+            </Collapse>
+        </Fragment>
+    )
+}
+
+export default CatalogFilter
diff --git a/frontend/src/features/Catalog/CatalogTable.tsx b/frontend/src/features/Catalog/CatalogTable.tsx
index d1318bf258747b43e1c2979a78767aa316740bf0..098cb784ed376cd743d50b1501e744e499328204 100644
--- a/frontend/src/features/Catalog/CatalogTable.tsx
+++ b/frontend/src/features/Catalog/CatalogTable.tsx
@@ -13,10 +13,10 @@ import { Link as RouterLink } from 'react-router-dom'
 import { CatalogItemDto } from '../../swagger/data-contracts'
 import ShowErrorIfPresent from '../Reusables/ShowErrorIfPresent'
 import ContentLoading from '../Reusables/ContentLoading'
-import axiosInstance from '../../api/api'
-
-const apiError =
-    'Error while fetching data from the server, please try again later.'
+import { RootState } from '../redux/store'
+import { useDispatch, useSelector } from 'react-redux'
+import { consumeError, setLoading } from './catalogSlice'
+import { fetchItems } from './catalogThunks'
 
 // Catalog table component
 const CatalogTable = () => {
@@ -28,9 +28,12 @@ const CatalogTable = () => {
         rowsPerPage[0]
     )
 
-    const [items, setItems] = useState<CatalogItemDto[]>([])
-    const [areItemsLoading, setAreItemsLoading] = useState(true)
-    const [err, setErr] = useState<string | undefined>(undefined)
+    // Subscribe to the store
+    const items = useSelector((state: RootState) => state.catalog.items)
+    const loading = useSelector((state: RootState) => state.catalog.loading)
+    const apiError = useSelector((state: RootState) => state.catalog.error)
+
+    const [displayError, setDisplayError] = useState<string | undefined>(undefined)
 
     // When changing rows per page set the selected number and reset to the first page
     const onRowsPerPageChange = (
@@ -40,28 +43,27 @@ const CatalogTable = () => {
         setPage(0)
     }
 
-    // Use effect hook to fetch rows from the server
+    const dispatch = useDispatch()
+
     useEffect(() => {
-        // Function to fetch items from the API
-        const fetchItems = async () => {
-            try {
-                const { data, status } = await axiosInstance.get(
-                    '/catalog-items'
-                )
-                if (status !== 200) {
-                    setErr(apiError)
-                    return
-                }
+        // Fetch items when the component is mounted
+        // This will automatically search whenever the filter changes
+        dispatch(fetchItems())
 
-                setItems(data)
-                setAreItemsLoading(false)
-            } catch (err: any) {
-                setErr(apiError)
-            }
+        return () => {
+            // Invalidate the state when unmounting so that the old list is not rerendered when the user returns to the page
+            dispatch(setLoading())
+        }
+    }, [dispatch])
+
+    // Use effect to read the error and consume it
+    useEffect(() => {
+        if (apiError) {
+            setDisplayError(apiError)
+            dispatch(consumeError())
         }
+    }, [apiError, dispatch])
 
-        fetchItems()
-    }, [])
 
     // Name of columns in the header
     const columns = [
@@ -107,10 +109,10 @@ const CatalogTable = () => {
 
     return (
         <Fragment>
-            <ShowErrorIfPresent err={err} />
-            {areItemsLoading && !err ? <ContentLoading /> : null}
-            {!areItemsLoading && !err ? (
-                <Fragment>
+            <ShowErrorIfPresent err={displayError} />
+            {loading && !displayError ? <ContentLoading /> : null}
+            {!loading && !displayError ? (
+                 <Fragment>
                     <TableContainer>
                         <Table
                             stickyHeader
diff --git a/frontend/src/features/Catalog/catalogSlice.tsx b/frontend/src/features/Catalog/catalogSlice.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..cf4248e58922d77fefcee117af0750737d2f0696
--- /dev/null
+++ b/frontend/src/features/Catalog/catalogSlice.tsx
@@ -0,0 +1,62 @@
+import { createSlice } from '@reduxjs/toolkit'
+import { CatalogItemDto } from '../../swagger/data-contracts'
+import { fetchItems } from './catalogThunks'
+
+export interface CatalogFilter {
+    name?: string
+    type?: string
+    country?: string
+}
+
+export interface CatalogState {
+    items: CatalogItemDto[] // list of all fetched items
+    filter: CatalogFilter // filter object
+    loading: boolean // whether the catalog is loading
+    error?: string
+}
+
+const initialState: CatalogState = {
+    items: [],
+    filter: {},
+    loading: true,
+    error: undefined,
+}
+
+const catalogSlice = createSlice({
+    name: 'catalog',
+    initialState,
+    reducers: {
+        setFilter: (state, action) => ({
+            ...state,
+            filter: {...action.payload},
+        }),
+        clearFilter: (state, action) => ({
+            ...state,
+            loading: true,
+            filter: {},
+        }),
+        clear: (state) => ({ ...initialState }),
+        setLoading: (state) => ({ ...state, loading: true }),
+        consumeError: (state) => ({ ...state, error: undefined }),
+    },
+    extraReducers: (builder) => {
+        builder.addCase(fetchItems.pending, (state) => ({
+            ...state,
+            loading: true,
+        }))
+        builder.addCase(fetchItems.fulfilled, (state, action) => ({
+            ...state,
+            items: action.payload,
+            loading: false,
+        }))
+        builder.addCase(fetchItems.rejected, (state, action) => ({
+            ...state,
+            loading: false,
+            error: action.payload as string,
+        }))
+    },
+})
+
+export const { setFilter, clearFilter, clear, setLoading, consumeError } = catalogSlice.actions
+const reducer = catalogSlice.reducer
+export default reducer
diff --git a/frontend/src/features/Catalog/catalogThunks.tsx b/frontend/src/features/Catalog/catalogThunks.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..7e2e9efba14e7eab57e4d235ead8e6a46d308e1e
--- /dev/null
+++ b/frontend/src/features/Catalog/catalogThunks.tsx
@@ -0,0 +1,40 @@
+import { createAsyncThunk } from '@reduxjs/toolkit'
+import axiosInstance from '../../api/api'
+import { CatalogFilter, CatalogState } from './catalogSlice'
+
+const apiError = 'Error, server is currently unavailable.'
+
+// Builds query string from the filter object
+const buildQuery = (catalogFilter: CatalogFilter): string => {
+    return Object.entries(catalogFilter).length === 0
+        ? ''
+        : `?${Object.entries(catalogFilter)
+              .map(([key, value]) => `${key}=${value}`)
+              .join('&')}`
+}
+
+// Thunk to fetch catalog items from the API
+export const fetchItems = createAsyncThunk(
+    'catalog/fetchItems',
+    async (dispatch, { getState }) => {
+        try {
+            // To make typescript happy we fool it like this
+            const { catalog } = getState() as { catalog: CatalogState }
+
+            
+            // Send request with the filter
+            const { data, status } = await axiosInstance.get(
+                `/catalog-items${buildQuery(catalog.filter)}`
+            )
+
+            // If the request was successful return the items
+            if (status === 200) {
+                return data
+            }
+
+            return Promise.reject(apiError)
+        } catch (err: any) {
+            return Promise.reject(apiError)
+        }
+    }
+)
diff --git a/frontend/src/features/redux/store.ts b/frontend/src/features/redux/store.ts
index 945ae90c9d538c1ae139d50390caf2e7d74cd1b8..b3addad9a154e47a3e64b670129b041ac23c9582 100644
--- a/frontend/src/features/redux/store.ts
+++ b/frontend/src/features/redux/store.ts
@@ -1,15 +1,25 @@
-
 import { applyMiddleware, combineReducers, createStore } from 'redux'
 import { persistStore } from 'redux-persist'
 import thunk from 'redux-thunk'
 import userReducer from '../Auth/userSlice'
 import themeReducer from '../Theme/themeReducer'
+import catalogReducer from '../Catalog/catalogSlice'
+import { composeWithDevTools } from 'redux-devtools-extension'
 
+const composeEnhancers = composeWithDevTools({})
 
 // Store holds shared state in the application
 const store = createStore(
-    combineReducers({ user: userReducer, theme: themeReducer }),
-    applyMiddleware(thunk) // Thunk middleware so we can async fetch data from the api
+    combineReducers({
+        user: userReducer,
+        theme: themeReducer,
+        catalog: catalogReducer,
+    }),
+    process.env.REACT_APP_DEV_ENV === 'true'
+        ? composeEnhancers(
+              applyMiddleware(thunk) // Thunk middleware so we can async fetch data from the api
+          )
+        : applyMiddleware(thunk)
 )
 
 export default store
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 6d4c9893b26533255acc370cbd70a49d1a000cbd..9d8e362f519e347cb04044db818869c027fcf4cf 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -15,11 +15,11 @@ injectStore(store)
 ReactDOM.render(
     <Provider store={store}>
         <PersistGate loading={null} persistor={persistor}>
-            <React.StrictMode>
+            {/* <React.StrictMode> */}
                 <BrowserRouter>
                     <App />
                 </BrowserRouter>
-            </React.StrictMode>
+            {/* </React.StrictMode> */}
         </PersistGate>
     </Provider>,
     document.getElementById('root')
diff --git a/frontend/src/swagger/CatalogItems.ts b/frontend/src/swagger/CatalogItems.ts
index cfd3c2ee13dc18620af08cf7a5166c478a87d4c6..1b0cb076bfdfa819336b76458474a7c038f2a7d8 100644
--- a/frontend/src/swagger/CatalogItems.ts
+++ b/frontend/src/swagger/CatalogItems.ts
@@ -25,7 +25,6 @@ export class CatalogItems<SecurityDataType = unknown> extends HttpClient<Securit
     this.request<CatalogItemDto, any>({
       path: `/catalog-items/${id}`,
       method: "GET",
-      format: "json",
       ...params,
     });
   /**
diff --git a/frontend/src/swagger/Path.ts b/frontend/src/swagger/Path.ts
new file mode 100644
index 0000000000000000000000000000000000000000..945e865cab46eef1d5730ad761a1e26ad0e6ef08
--- /dev/null
+++ b/frontend/src/swagger/Path.ts
@@ -0,0 +1,30 @@
+/* eslint-disable */
+/* tslint:disable */
+/*
+ * ---------------------------------------------------------------
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API        ##
+ * ##                                                           ##
+ * ## AUTHOR: acacode                                           ##
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
+ * ---------------------------------------------------------------
+ */
+
+import { PathDto } from "./data-contracts";
+import { HttpClient, RequestParams } from "./http-client";
+
+export class Path<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
+  /**
+   * No description
+   *
+   * @tags path-controller
+   * @name GetPath
+   * @request GET:/path
+   */
+  getPath = (query: { pathDto: PathDto }, params: RequestParams = {}) =>
+    this.request<PathDto, any>({
+      path: `/path`,
+      method: "GET",
+      query: query,
+      ...params,
+    });
+}
diff --git a/frontend/src/swagger/data-contracts.ts b/frontend/src/swagger/data-contracts.ts
index c8808aa6e24927ef96bdf5065e7c68526ab55984..07a88c83782cb93738f8ae8b4f31a6f7fce5d009 100644
--- a/frontend/src/swagger/data-contracts.ts
+++ b/frontend/src/swagger/data-contracts.ts
@@ -13,20 +13,21 @@ export interface CatalogItemDto {
   /** @format uuid */
   id?: string;
   name?: string;
-
-  /** @format int32 */
-  certainty?: number;
+  alternativeNames?: string[];
+  writtenForms?: string[];
+  types?: string[];
+  countries?: string[];
+  bibliography?: string[];
 
   /** @format double */
   longitude?: number;
 
   /** @format double */
   latitude?: number;
-  bibliography?: string[];
-  countries?: string[];
-  writtenForms?: string[];
-  alternativeNames?: string[];
-  types?: string[];
+
+  /** @format int32 */
+  certainty?: number;
+  description?: string;
 }
 
 export interface PasswordDto {
@@ -51,3 +52,8 @@ export interface TitlePageDto {
   title?: string;
   content?: string;
 }
+
+export interface PathDto {
+  text?: string;
+  foundCatalogItems?: CatalogItemDto[][];
+}
diff --git a/frontend/src/swagger/http-client.ts b/frontend/src/swagger/http-client.ts
index e994ab9d1446ea82fd72e2afd648f81053cfcc16..ab339058ae540160ed08247a257d1a8fc896b280 100644
--- a/frontend/src/swagger/http-client.ts
+++ b/frontend/src/swagger/http-client.ts
@@ -54,7 +54,7 @@ export enum ContentType {
 }
 
 export class HttpClient<SecurityDataType = unknown> {
-  public baseUrl: string = "/api";
+  public baseUrl: string = "http://localhost:8080";
   private securityData: SecurityDataType | null = null;
   private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
   private abortControllers = new Map<CancelToken, AbortController>();
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 42913e2efcc6e390a76f6c744b6a3862f7387752..9a33cf0b9343581e44de201301b6a6257ff466e3 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -7759,6 +7759,11 @@ redent@^3.0.0:
     indent-string "^4.0.0"
     strip-indent "^3.0.0"
 
+redux-devtools-extension@^2.13.9:
+  version "2.13.9"
+  resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz#6b764e8028b507adcb75a1cae790f71e6be08ae7"
+  integrity sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==
+
 redux-persist@*, redux-persist@^6.0.0:
   version "6.0.0"
   resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"