diff --git a/.gitignore b/.gitignore
index ad547b6..a2868de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,4 +15,7 @@ playwright/.cache/
 # Sass cache dir
 .sass-cache/
 
-.idea/
\ No newline at end of file
+.idea/
+
+# Ignore database file
+compareware.db
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 9f44832..b9ca793 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8,7 +8,7 @@ version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"
 dependencies = [
- "bitflags",
+ "bitflags 2.6.0",
  "bytes",
  "futures-core",
  "futures-sink",
@@ -29,7 +29,7 @@ dependencies = [
  "actix-service",
  "actix-utils",
  "actix-web",
- "bitflags",
+ "bitflags 2.6.0",
  "bytes",
  "derive_more",
  "futures-core",
@@ -52,9 +52,9 @@ dependencies = [
  "actix-rt",
  "actix-service",
  "actix-utils",
- "ahash",
+ "ahash 0.8.11",
  "base64",
- "bitflags",
+ "bitflags 2.6.0",
  "brotli",
  "bytes",
  "bytestring",
@@ -127,7 +127,7 @@ dependencies = [
  "actix-utils",
  "futures-core",
  "futures-util",
- "mio",
+ "mio 1.0.3",
  "socket2",
  "tokio",
  "tracing",
@@ -169,7 +169,7 @@ dependencies = [
  "actix-service",
  "actix-utils",
  "actix-web-codegen",
- "ahash",
+ "ahash 0.8.11",
  "bytes",
  "bytestring",
  "cfg-if",
@@ -233,6 +233,17 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "ahash"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
 [[package]]
 name = "ahash"
 version = "0.8.11"
@@ -398,7 +409,7 @@ dependencies = [
  "miniz_oxide",
  "object",
  "rustc-demangle",
- "windows-targets",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -510,6 +521,12 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
 [[package]]
 name = "bitflags"
 version = "2.6.0"
@@ -729,7 +746,10 @@ dependencies = [
  "leptos_actix",
  "leptos_meta",
  "leptos_router",
+ "mio 0.8.11",
  "nostr-sdk",
+ "paste",
+ "rusqlite",
  "secp256k1 0.30.0",
  "serde",
  "serde_json",
@@ -982,6 +1002,18 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
 [[package]]
 name = "flate2"
 version = "1.0.35"
@@ -1227,6 +1259,15 @@ dependencies = [
  "crunchy",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+dependencies = [
+ "ahash 0.7.8",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.13.2"
@@ -1239,7 +1280,7 @@ version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
- "ahash",
+ "ahash 0.8.11",
  "allocator-api2",
 ]
 
@@ -1254,6 +1295,15 @@ dependencies = [
  "foldhash",
 ]
 
+[[package]]
+name = "hashlink"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
+dependencies = [
+ "hashbrown 0.11.2",
+]
+
 [[package]]
 name = "hex-conservative"
 version = "0.1.2"
@@ -1810,6 +1860,16 @@ version = "0.2.168"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
 
+[[package]]
+name = "libsqlite3-sys"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
+dependencies = [
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "linear-map"
 version = "1.2.0"
@@ -1937,6 +1997,18 @@ dependencies = [
  "adler2",
 ]
 
+[[package]]
+name = "mio"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "mio"
 version = "1.0.3"
@@ -2109,7 +2181,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -2380,7 +2452,7 @@ version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
 dependencies = [
- "bitflags",
+ "bitflags 2.6.0",
 ]
 
 [[package]]
@@ -2447,6 +2519,21 @@ dependencies = [
  "thiserror 1.0.69",
 ]
 
+[[package]]
+name = "rusqlite"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a"
+dependencies = [
+ "bitflags 1.3.2",
+ "fallible-iterator",
+ "fallible-streaming-iterator",
+ "hashlink",
+ "libsqlite3-sys",
+ "memchr",
+ "smallvec",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.24"
@@ -2990,7 +3077,7 @@ dependencies = [
  "backtrace",
  "bytes",
  "libc",
- "mio",
+ "mio 1.0.3",
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
@@ -3284,6 +3371,12 @@ version = "0.15.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c"
 
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
 [[package]]
 name = "version_check"
 version = "0.9.5"
@@ -3414,13 +3507,22 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -3429,7 +3531,22 @@ version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
 ]
 
 [[package]]
@@ -3438,28 +3555,46 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
  "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
 ]
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
 [[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
 [[package]]
 name = "windows_i686_gnu"
 version = "0.52.6"
@@ -3472,24 +3607,48 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
 [[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.52.6"
diff --git a/Cargo.toml b/Cargo.toml
index d5a1264..3794533 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,7 +15,9 @@ leptos = { version = "0.6" }
 leptos_meta = { version = "0.6" }
 leptos_actix = { version = "0.6", optional = true }
 leptos_router = { version = "0.6" }
+paste = "1.0"
 wasm-bindgen = "=0.2.99"
+rusqlite = { version = "0.27.0", optional = true}
 serde = { version = "1.0", features = ["derive"] }
 uuid = { version = "1.0", features = ["v4"] }
 web-sys = { version = "0.3", features = ["Event"] }
@@ -28,8 +30,10 @@ wasm-bindgen-futures = "0.4"
 serde_json="1.0.133"
 thiserror = "2.0.9"
 zerofrom = "0.1"
+mio = "0.8" 
 
 [features]
+default = ["ssr"]
 csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
 hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
 ssr = [
@@ -39,6 +43,7 @@ ssr = [
   "leptos/ssr",
   "leptos_meta/ssr",
   "leptos_router/ssr",
+  "dep:rusqlite"
 ]
 
 # Override secp256k1's default features
diff --git a/src/api.rs b/src/api.rs
new file mode 100644
index 0000000..de3d6b7
--- /dev/null
+++ b/src/api.rs
@@ -0,0 +1,65 @@
+#[cfg(feature = "ssr")]
+use actix_web::{web, HttpResponse};
+#[cfg(feature = "ssr")]
+use crate::db::{Database, DbItem};
+#[cfg(feature = "ssr")]
+use std::sync::Arc;
+#[cfg(feature = "ssr")]
+use tokio::sync::Mutex;
+
+#[cfg(feature = "ssr")]
+pub async fn get_items(db: web::Data<Arc<Mutex<Database>>>) -> HttpResponse {
+    let db = db.lock().await;
+    match db.get_items().await {
+        Ok(items) => HttpResponse::Ok().json(items),
+        Err(err) => {
+            leptos::logging::error!("Failed to fetch items: {:?}", err);
+            HttpResponse::InternalServerError().body("Failed to fetch items")
+        }
+    }
+}
+
+#[cfg(feature = "ssr")]
+pub async fn create_item(
+    db: web::Data<Arc<Mutex<Database>>>,
+    item: web::Json<DbItem>,
+) -> HttpResponse {
+    let db = db.lock().await;
+    match db.insert_item(&item.into_inner()).await {
+        Ok(_) => HttpResponse::Ok().body("Item inserted"),
+        Err(err) => {
+            leptos::logging::error!("Failed to insert item: {:?}", err);
+            HttpResponse::InternalServerError().body("Failed to insert item")
+        }
+    }
+}
+
+#[cfg(feature = "ssr")]
+pub async fn delete_item(
+    db: web::Data<Arc<Mutex<Database>>>,
+    item_id: web::Path<String>,
+) -> HttpResponse {
+    let db = db.lock().await;
+    match db.delete_item(&item_id).await {
+        Ok(_) => HttpResponse::Ok().body("Item deleted"),
+        Err(err) => {
+            leptos::logging::error!("Failed to delete item: {:?}", err);
+            HttpResponse::InternalServerError().body("Failed to delete item")
+        }
+    }
+}
+
+#[cfg(feature = "ssr")]
+pub async fn delete_property(
+    db: web::Data<Arc<Mutex<Database>>>,
+    property: web::Path<String>,
+) -> HttpResponse {
+    let db = db.lock().await;
+    match db.delete_property(&property).await {
+        Ok(_) => HttpResponse::Ok().body("Property deleted"),
+        Err(err) => {
+            leptos::logging::error!("Failed to delete property: {:?}", err);
+            HttpResponse::InternalServerError().body("Failed to delete property")
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/components/items_list.rs b/src/components/items_list.rs
index 53aae06..1e8a754 100644
--- a/src/components/items_list.rs
+++ b/src/components/items_list.rs
@@ -1,7 +1,7 @@
 use crate::components::editable_cell::EditableCell;
 use crate::components::editable_cell::InputType;
 use leptos::*;
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
 use uuid::Uuid;
 use leptos::logging::log;
 use crate::models::item::Item;
@@ -16,11 +16,24 @@ struct WikidataSuggestion {
     description: Option<String>,
 }
 
+
+#[derive(Deserialize, Debug)]
+struct DbItem {
+    id: String,
+    name: String,
+    description: String,
+    wikidata_id: Option<String>,
+    custom_properties: String,
+}
+
 #[component]
 pub fn ItemsList(
     items: ReadSignal<Vec<Item>>,
     set_items: WriteSignal<Vec<Item>>,
 ) -> impl IntoView {
+    // State to track selected properties
+    let (selected_properties, set_selected_properties) = create_signal(HashMap::<String, bool>::new());
+    
     // State to track the currently focused cell
     let (focused_cell, set_focused_cell) = create_signal(None::<String>);
 
@@ -33,8 +46,67 @@ pub fn ItemsList(
     // cache to store fetched properties
     let (fetched_properties, set_fetched_properties) = create_signal(HashMap::<String, String>::new());
    
-    //signal to store the fetched property labels
+    // Signal to store the fetched property labels
     let (property_labels, set_property_labels) = create_signal(HashMap::<String, String>::new());
+    
+    spawn_local(async move {
+        match load_items_from_db().await {
+            Ok(loaded_items) => {
+                // Set the loaded items
+                if loaded_items.is_empty() {
+                    // Initialize with one empty item if the database is empty
+                    set_items.set(vec![Item {
+                        id: Uuid::new_v4().to_string(),
+                        name: String::new(),
+                        description: String::new(),
+                        wikidata_id: None,
+                        custom_properties: HashMap::new(),
+                    }]);
+                } else {
+                    set_items.set(loaded_items.clone());
+                }
+    
+                // Derive selected properties from the loaded items
+                let mut selected_props = HashMap::new();
+                let loaded_items_clone = loaded_items.clone();
+                for item in loaded_items {
+                    for (property, _) in item.custom_properties {
+                        selected_props.insert(property, true);
+                    }
+                }
+                set_selected_properties.set(selected_props);
+
+                // Update the custom_properties signal
+                let mut custom_props = Vec::new();
+                for item in loaded_items_clone {
+                    for (property, _) in &item.custom_properties {
+                        if !custom_props.iter().any(|p| p == property) {
+                            custom_props.push(property.clone());
+                        }
+                    }
+                }
+
+                let custom_props_clone = custom_props.clone();
+                set_custom_properties.set(custom_props);
+
+                // Fetch labels for the custom properties
+                let property_ids = custom_props_clone;
+                let labels = fetch_property_labels(property_ids).await;
+                set_property_labels.update(|labels_map| {
+                    for (key, value) in labels {
+                        labels_map.insert(key, value);
+                    }
+                });
+
+                log!("Items after loading: {:?}", items.get());
+            }
+            Err(err) => {
+                log!("Error loading items: {}", err);
+            }
+        }
+    });
+
+
     // Ensure there's an initial empty row
     if items.get().is_empty() {
         set_items.set(vec![Item {
@@ -46,6 +118,153 @@ pub fn ItemsList(
             custom_properties: HashMap::new(),
         }]);
     }
+    
+    // Function to send an item to the backend API
+    async fn save_item_to_db(item: Item, selected_properties: ReadSignal<HashMap<String, bool>>) {
+        // Use a reactive closure to access `selected_properties`
+        let custom_properties: HashMap<String, String> = (move || {
+            let selected_props = selected_properties.get(); // Access the signal inside a reactive closure
+            item.custom_properties
+                .into_iter()
+                .filter(|(key, _)| selected_props.contains_key(key)) // Use the extracted value
+                .collect()
+        })(); 
+
+        // Serialize `custom_properties` to a JSON string
+        let custom_properties = serde_json::to_string(&custom_properties).unwrap();
+    
+        // Create a new struct to send to the backend
+        #[derive(Serialize, Debug)]
+        struct ItemToSend {
+            id: String,
+            name: String,
+            description: String,
+            wikidata_id: Option<String>,
+            custom_properties: String, // JSON-encoded string
+        }
+    
+        let item_to_send = ItemToSend {
+            id: item.id,
+            name: item.name,
+            description: item.description,
+            wikidata_id: item.wikidata_id,
+            custom_properties, // Use the serialized string
+        };
+    
+        let response = gloo_net::http::Request::post("/api/items")
+            .json(&item_to_send)
+            .unwrap()
+            .send()
+            .await;
+    
+        match response {
+            Ok(resp) => {
+                if resp.status() == 200 {
+                    log!("Item saved to database: {:?}", item_to_send);
+                } else {
+                    log!("Failed to save item: {}", resp.status_text());
+                }
+            }
+            Err(err) => log!("Failed to save item: {:?}", err),
+        }
+    }
+
+    //function to load items from database
+    async fn load_items_from_db() -> Result<Vec<Item>, String> {
+        let response = gloo_net::http::Request::get("/api/items")
+            .send()
+            .await
+            .map_err(|err| format!("Failed to fetch items: {:?}", err))?;
+    
+        if response.status() == 200 {
+            // Deserialize into Vec<DbItem>
+            log!("Loading items from DB...");
+            let db_items = response
+                .json::<Vec<DbItem>>()
+                .await
+                .map_err(|err| format!("Failed to parse items: {:?}", err))?;
+
+            log!("Deserialized DB items: {:?}", db_items);
+    
+            // Convert DbItem to Item
+            let items = db_items
+                .into_iter()
+                .map(|db_item| {
+                    // Deserialize `custom_properties` from a JSON string to a HashMap
+                    let custom_properties: HashMap<String, String> =
+                        serde_json::from_str(&db_item.custom_properties)
+                            .unwrap_or_default(); // Fallback to an empty HashMap if deserialization fails
+                    
+                    log!("Loaded item: {:?}", db_item.id);
+                    log!("Custom properties: {:?}", custom_properties);
+                    
+                    Item {
+                        id: db_item.id,
+                        name: db_item.name,
+                        description: db_item.description,
+                        wikidata_id: db_item.wikidata_id,
+                        custom_properties, // Deserialized HashMap
+                    }
+                })
+                .collect();
+            log!("Converted items: {:?}", items);
+            Ok(items)
+        } else {
+            Err(format!("Failed to fetch items: {}", response.status_text()))
+        }
+    }
+
+    // remove an item
+    let remove_item = move |index: usize| {
+        let item_id = items.get()[index].id.clone();
+        spawn_local(async move {
+            let response = gloo_net::http::Request::delete(&format!("/api/items/{}", item_id))
+                .send()
+                .await;
+            match response {
+                Ok(resp) => {
+                    if resp.status() == 200 {
+                        set_items.update(|items| {
+                            items.remove(index);
+                        });
+                        log!("Item deleted: {}", item_id);
+                    } else {
+                        log!("Failed to delete item: {}", resp.status_text());
+                    }
+                }
+                Err(err) => log!("Failed to delete item: {:?}", err),
+            }
+        });
+    };
+
+    let remove_property = move |property: String| {
+        spawn_local(async move {
+            let response = gloo_net::http::Request::delete(&format!("/api/properties/{}", property))
+                .send()
+                .await;
+            match response {
+                Ok(resp) => {
+                    if resp.status() == 200 {
+                        set_custom_properties.update(|props| {
+                            props.retain(|p| p != &property);
+                        });
+                        set_selected_properties.update(|selected| {
+                            selected.remove(&property);
+                        });
+                        set_items.update(|items| {
+                            for item in items {
+                                item.custom_properties.remove(&property);
+                            }
+                        });
+                        log!("Property deleted: {}", property);
+                    } else {
+                        log!("Failed to delete property: {}", resp.status_text());
+                    }
+                }
+                Err(err) => log!("Failed to delete property: {:?}", err),
+            }
+        });
+    };
 
     let (wikidata_suggestions, set_wikidata_suggestions) = create_signal(HashMap::<String, Vec<WikidataSuggestion>>::new());
 
@@ -164,10 +383,22 @@ pub fn ItemsList(
         set_custom_properties.update(|props| {
             if !props.contains(&property) && !property.is_empty() {
                 props.push(property.clone());
+
+                //update the selected_properties state when a new property is added
+                set_selected_properties.update(|selected| {
+                    selected.insert(property.clone(), true);
+                });
+
                 // Ensure the grid updates reactively
                 set_items.update(|items| {
                     for item in items {
                         item.custom_properties.entry(property.clone()).or_insert_with(|| "".to_string());
+                        
+                        // Save the updated item to the database
+                        let item_clone = item.clone();
+                        spawn_local(async move {
+                            save_item_to_db(item_clone, selected_properties).await;
+                        });
                     }
                 });
 
@@ -193,7 +424,7 @@ pub fn ItemsList(
                     let property_clone = property.clone();
                     spawn_local(async move {
                         let properties = fetch_item_properties(&wikidata_id, set_fetched_properties, set_property_labels).await;
-                        log!("Fetched properties for Wikidata ID {}: {:?}", wikidata_id, properties);
+                        // log!("Fetched properties for Wikidata ID {}: {:?}", wikidata_id, properties);
                         if let Some(value) = properties.get(&property_clone) {
                             set_items.update(|items| {
                                 if let Some(item) = items.iter_mut().find(|item| item.wikidata_id.as_ref().unwrap() == &wikidata_id) {
@@ -237,31 +468,34 @@ pub fn ItemsList(
                         item.custom_properties.insert(field.to_string(), value.clone());
                     }
                 }
-            }
 
+                // Save the updated item to the database
+                let item_clone = item.clone();
+                spawn_local(async move {
+                    save_item_to_db(item_clone, selected_properties).await;
+                });
+            }
             // Automatically add a new row when editing the last row
             if index == items.len() - 1 && !value.is_empty() {
-                items.push(Item {
+                let new_item = Item {
                     id: Uuid::new_v4().to_string(),
                     name: String::new(),
                     description: String::new(),
                     // reviews: vec![],
                     wikidata_id: None,
                     custom_properties: HashMap::new(),
+                };
+                items.push(new_item.clone());
+
+                // Save the new item to the database
+                spawn_local(async move {
+                    save_item_to_db(new_item, selected_properties).await;
                 });
             }
             log!("Items updated: {:?}", items);
         });
     };
 
-
-    // Remove an item
-    let remove_item = move |index: usize| {
-        set_items.update(|items| {
-                items.remove(index);
-        });
-    };
-
     // List of properties to display as rows
     let properties = vec!["Name", "Description", "Actions"];
 
@@ -360,7 +594,7 @@ pub fn ItemsList(
                                                                                         let set_property_labels = set_property_labels.clone();
                                                                                         spawn_local(async move {
                                                                                             let properties = fetch_item_properties(&wikidata_id, set_fetched_properties, set_property_labels).await;
-                                                                                            log!("Fetched properties for Wikidata ID {}: {:?}", wikidata_id, properties);
+                                                                                            // log!("Fetched properties for Wikidata ID {}: {:?}", wikidata_id, properties);
                                                                                             
                                                                                             // Populate the custom properties for the new item
                                                                                             set_items.update(|items| {
@@ -426,36 +660,56 @@ pub fn ItemsList(
                     // Dynamically adding custom properties as columns
                     {move || {
                         let custom_props = custom_properties.get().clone();
+                        log!("Rendering custom properties: {:?}", custom_props);
                         custom_props.into_iter().map(move |property| {
                             let property_clone = property.clone();
                             let property_label = property_labels.get().get(&property_clone).cloned().unwrap_or_else(|| property_clone.clone());
+                            let property_clone_for_button = property_clone.clone();
+                            let property_clone_for_cells = property_clone.clone(); 
                             view! {
                                 <tr>
-                                    <td>{ property_label }</td>
+                                    <td>
+                                        { property_label }
+                                        <button class="delete-property" on:click=move |_| {
+                                            log!("Deleting property: {}", property_clone_for_button);
+                                            remove_property(property_clone_for_button.clone());
+                                            set_custom_properties.update(|props| {
+                                                props.retain(|p| p != &property_clone_for_button);
+                                            });
+                                            set_selected_properties.update(|selected| {
+                                                selected.remove(&property_clone_for_button);
+                                            });
+                                            set_items.update(|items| {
+                                                for item in items {
+                                                    item.custom_properties.remove(&property_clone_for_button);
+                                                }
+                                            });
+                                        }>{ "Delete" }</button>
+                                    </td>
                                     {move || {
-                                        let property_clone = property_clone.clone(); // Clone `property_clone` again for the inner closure
+                                        let property_clone_for_cells = property_clone.clone();
                                         items.get().iter().enumerate().map(move |(index, item)| {
-                                            let property_clone_for_closure = property_clone.clone();
-                                            view! {
-                                                <td>
-                                                    <EditableCell
-                                                        value=item.custom_properties.get(&property_clone).cloned().unwrap_or_default()
-                                                        on_input=move |value| update_item(index, &property_clone_for_closure, value)
-                                                        key=Arc::new(format!("custom-{}-{}", property_clone, index))
-                                                        focused_cell=focused_cell
-                                                        set_focused_cell=set_focused_cell.clone()
-                                                        on_focus=Some(Callback::new(move |_| {
-                                                            log!("Custom property input focused");
-                                                        }))
-                                                        on_blur=Some(Callback::new(move |_| {
-                                                            log!("Custom property input blurred");
-                                                        }))
-                                                        input_type=InputType::TextArea
-                                                    />
-                                                </td>
-                                            }
-                                        }).collect::<Vec<_>>()
-                                    }}
+                                        let property_clone_for_closure = property_clone_for_cells.clone();
+                                        view! {
+                                            <td>
+                                                <EditableCell
+                                                    value=item.custom_properties.get(&property_clone_for_closure).cloned().unwrap_or_default()
+                                                    on_input=move |value| update_item(index, &property_clone_for_closure, value)
+                                                    key=Arc::new(format!("custom-{}-{}", property_clone_for_cells, index))
+                                                    focused_cell=focused_cell
+                                                    set_focused_cell=set_focused_cell.clone()
+                                                    on_focus=Some(Callback::new(move |_| {
+                                                        log!("Custom property input focused");
+                                                    }))
+                                                    on_blur=Some(Callback::new(move |_| {
+                                                        log!("Custom property input blurred");
+                                                    }))
+                                                    input_type=InputType::TextArea
+                                                />
+                                            </td>
+                                        }
+                                    }).collect::<Vec<_>>()}
+                                    }
                                 </tr>
                             }
                         }).collect::<Vec<_>>()
diff --git a/src/db.rs b/src/db.rs
new file mode 100644
index 0000000..16fe958
--- /dev/null
+++ b/src/db.rs
@@ -0,0 +1,136 @@
+#[cfg(feature = "ssr")]
+mod db_impl {
+    use rusqlite::{Connection, Error};
+    use serde::{Deserialize, Serialize};
+    use std::sync::Arc;
+    use tokio::sync::Mutex;
+    use leptos::logging;
+
+    // Define a struct to represent a database connection
+    #[derive(Debug)]
+    pub struct Database {
+        conn: Arc<Mutex<Connection>>,
+    }
+
+    impl Database {
+        // Create a new database connection
+        pub fn new(db_path: &str) -> Result<Self, Error> {
+            let conn = Connection::open(db_path)?;
+            logging::log!("Database connection established at: {}", db_path); 
+            Ok(Database {
+                conn: Arc::new(Mutex::new(conn)),
+            })
+        }
+
+        // Create the database schema
+        pub async fn create_schema(&self) -> Result<(), Error> {
+            let conn = self.conn.lock().await;
+            conn.execute_batch(
+                "CREATE TABLE IF NOT EXISTS items (
+                    id TEXT PRIMARY KEY,
+                    name TEXT NOT NULL,
+                    description TEXT,
+                    wikidata_id TEXT,
+                    custom_properties TEXT
+                );",
+            )?;
+            logging::log!("Database schema created or verified");
+            Ok(())
+        }
+
+        // Insert a new item into the database
+        pub async fn insert_item(&self, item: &DbItem) -> Result<(), Error> {
+            let conn = self.conn.lock().await;
+            let wikidata_id = item.wikidata_id.as_ref().map(|s| s.as_str()).unwrap_or("");
+            conn.execute(
+            "INSERT INTO items (id, name, description, wikidata_id, custom_properties)
+             VALUES (?, ?, ?, ?, ?)
+             ON CONFLICT(id) DO UPDATE SET
+                 name = excluded.name,
+                 description = excluded.description,
+                 wikidata_id = excluded.wikidata_id,
+                 custom_properties = excluded.custom_properties;",
+            &[
+                &item.id,
+                &item.name,
+                &item.description,
+                &wikidata_id.to_string(),
+                &item.custom_properties,
+            ],
+        )?;
+            logging::log!("Item inserted: {}", item.id);
+            Ok(())
+        }
+
+        pub async fn delete_item(&self, item_id: &str) -> Result<(), Error> {
+            let conn = self.conn.lock().await;
+            conn.execute("DELETE FROM items WHERE id = ?", &[item_id])?;
+            logging::log!("Item deleted: {}", item_id);
+            Ok(())
+        }
+
+        pub async fn delete_property(&self, property: &str) -> Result<(), Error> {
+            let conn = self.conn.lock().await;
+            let query = format!("UPDATE items SET custom_properties = json_remove(custom_properties, '$.{}')", property);
+            conn.execute(&query, []).map_err(|e| Error::from(e))?;
+            logging::log!("Property deleted: {}", property);
+            Ok(())
+        }
+        
+        // Retrieve all items from the database
+        pub async fn get_items(&self) -> Result<Vec<DbItem>, Error> {
+            let conn = self.conn.lock().await;
+            let mut stmt = conn.prepare("SELECT * FROM items;")?;
+            let items = stmt.query_map([], |row| {
+                Ok(DbItem {
+                    id: row.get(0)?,
+                    name: row.get(1)?,
+                    description: row.get(2)?,
+                    wikidata_id: row.get(3)?,
+                    custom_properties: row.get(4)?,
+                })
+            })?;
+            let mut result = Vec::new();
+            for item in items {
+                result.push(item?);
+            }
+            logging::log!("Fetched {} items from the database", result.len()); // Log with Leptos
+            Ok(result)
+        }
+    }
+
+    // Define a struct to represent an item in the database
+    #[derive(Debug, Deserialize, Serialize, Clone)]
+    pub struct DbItem {
+        pub id: String,
+        pub name: String,
+        pub description: String,
+        pub wikidata_id: Option<String>,
+        pub custom_properties: String,
+    }
+
+    // Implement conversion from DbItem to a JSON-friendly format
+    #[derive(Debug, Deserialize, Serialize, Clone)]
+    pub struct ItemResponse {
+        pub id: String,
+        pub name: String,
+        pub description: String,
+        pub wikidata_id: Option<String>,
+        pub custom_properties: String,
+    }
+
+    impl From<DbItem> for ItemResponse {
+        fn from(item: DbItem) -> Self {
+            ItemResponse {
+                id: item.id,
+                name: item.name,
+                description: item.description,
+                wikidata_id: item.wikidata_id,
+                custom_properties: item.custom_properties,
+            }
+        }
+    }
+}
+
+#[cfg(feature = "ssr")]
+pub use db_impl::{Database, DbItem, ItemResponse};
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 10f7ef7..a2a7cab 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,9 @@ pub mod app;
 pub mod components;
 pub mod models;
 pub mod nostr;
+pub mod api;
+#[cfg(feature = "ssr")]
+pub mod db;
 
 
 #[cfg(feature = "hydrate")]
diff --git a/src/main.rs b/src/main.rs
index 535b829..b2a782a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,27 +6,55 @@ async fn main() -> std::io::Result<()> {
     use leptos::*;
     use leptos_actix::{generate_route_list, LeptosRoutes};
     use compareware::app::*;
+    use compareware::db::{Database, DbItem};
+    use compareware::api::{get_items, create_item, delete_item, delete_property}; // Import API handlers
+    use std::sync::Arc;
+    use tokio::sync::Mutex;
 
+    // Load configuration
     let conf = get_configuration(None).await.unwrap();
     let addr = conf.leptos_options.site_addr;
+
+    // Initialize the database
+    let db = Database::new("compareware.db").unwrap();
+    db.create_schema().await.unwrap(); // Ensure the schema is created
+    let db = Arc::new(Mutex::new(db)); // Wrap the database in an Arc<Mutex<T>> for shared state
+
     // Generate the list of routes in your Leptos App
     let routes = generate_route_list(App);
     println!("listening on http://{}", &addr);
 
+    // Start the Actix Web server
     HttpServer::new(move || {
         let leptos_options = &conf.leptos_options;
         let site_root = &leptos_options.site_root;
+        let db = db.clone(); // Clone the Arc for each worker
+
 
         App::new()
-            // serve JS/WASM/CSS from `pkg`
+            // Register custom API routes BEFORE Leptos server functions
+            .service(
+                web::scope("/api")
+                    .route("/items", web::get().to(get_items)) // GET /api/items
+                    .route("/items", web::post().to(create_item)) // POST /api/items
+                    .route("/items/{id}", web::delete().to(delete_item)) // DELETE /api/items/{id}
+                    .route("/properties/{property}", web::delete().to(delete_property)), // DELETE /api/properties/{property}
+            )
+            // Register server functions
+            .route("/api/{tail:.*}", leptos_actix::handle_server_fns())
+            // Serve JS/WASM/CSS from `pkg`
             .service(Files::new("/pkg", format!("{site_root}/pkg")))
-            // serve other assets from the `assets` directory
+            // Serve other assets from the `assets` directory
             .service(Files::new("/assets", site_root))
-            // serve the favicon from /favicon.ico
+            // Serve the favicon from /favicon.ico
             .service(favicon)
+            // Register Leptos routes
             .leptos_routes(leptos_options.to_owned(), routes.to_owned(), App)
+            // Pass Leptos options to the app
             .app_data(web::Data::new(leptos_options.to_owned()))
-        //.wrap(middleware::Compress::default())
+            //.wrap(middleware::Compress::default())
+            // Pass the database as shared state
+            .app_data(web::Data::new(db))
     })
     .bind(&addr)?
     .run()
@@ -63,4 +91,4 @@ pub fn main() {
     console_error_panic_hook::set_once();
 
     leptos::mount_to_body(App);
-}
+}
\ No newline at end of file