Repository: Wulf/create-rust-app (language: rust)

Issue:
how to switch sqlite
I tried to use sqlite, but it didn't work. How do I switch to sqlite?
thanks


Discussion / hints:
Ah darn I just realized the helper crate defines `Connection` as a postgres connection type...

I'll have to do some refactoring to get it to work with other database, super sorry about this!~

Fix patch:
diff --git a/.gitignore b/.gitignore
index 1aba14ba..18b8fb99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
 .DS_Store
 /target/
-/.idea/
+.idea
 test-project/
diff --git a/Cargo.lock b/Cargo.lock
index e60f45bb..4f330559 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -332,6 +332,15 @@ dependencies = [
  "alloc-no-stdlib",
 ]
 
+[[package]]
+name = "android_system_properties"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "ansi_term"
 version = "0.11.0"
@@ -937,15 +946,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.19"
+version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
 dependencies = [
- "libc",
+ "iana-time-zone",
+ "js-sys",
  "num-integer",
  "num-traits",
  "serde",
  "time 0.1.43",
+ "wasm-bindgen",
  "winapi",
 ]
 
@@ -1233,6 +1244,7 @@ dependencies = [
  "chrono",
  "diesel_derives 2.0.0-rc.1",
  "itoa",
+ "libsqlite3-sys",
  "pq-sys",
  "r2d2",
  "uuid 0.8.2",
@@ -1950,6 +1962,19 @@ dependencies = [
  "webpki 0.21.4",
 ]
 
+[[package]]
+name = "iana-time-zone"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "js-sys",
+ "wasm-bindgen",
+ "winapi",
+]
+
 [[package]]
 name = "idna"
 version = "0.2.3"
@@ -2024,9 +2049,9 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.56"
+version = "0.3.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
+checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -2105,6 +2130,16 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "libsqlite3-sys"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f0455f2c1bc9a7caa792907026e469c1d91761fb0ea37cbb16427c77280cf35"
+dependencies = [
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "local-channel"
 version = "0.1.2"
@@ -2332,9 +2367,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.9.0"
+version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
+checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
 
 [[package]]
 name = "opaque-debug"
@@ -2654,9 +2689,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
 
 [[package]]
 name = "pq-sys"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
+checksum = "3b845d6d8ec554f972a2c5298aad68953fd64e7441e846075450b44656a016d1"
 dependencies = [
  "vcpkg",
 ]
@@ -3155,18 +3190,18 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
 
 [[package]]
 name = "serde"
-version = "1.0.137"
+version = "1.0.143"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
+checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.137"
+version = "1.0.143"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
+checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
 dependencies = [
  "proc-macro2 1.0.39",
  "quote 1.0.15",
@@ -3175,9 +3210,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.81"
+version = "1.0.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
+checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
 dependencies = [
  "itoa",
  "ryu",
@@ -3391,9 +3426,9 @@ dependencies = [
 
 [[package]]
 name = "tera"
-version = "1.15.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3cac831b615c25bcef632d1cabf864fa05813baad3d526829db18eb70e8b58d"
+checksum = "1d4685e72cb35f0eb74319c8fe2d3b61e93da5609841cde2cb87fcc3bea56d20"
 dependencies = [
  "chrono",
  "chrono-tz",
@@ -3670,9 +3705,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
 
 [[package]]
 name = "tsync"
-version = "1.2.1"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0ab0312297ccbf7d91e2bec55eacb779c34ed52b49370c9c513be4e49305fd8"
+checksum = "617a68e82634585720535a038c7452942b2ef8671ae4d790191a298beecf658d"
 dependencies = [
  "structopt",
  "syn",
@@ -3964,9 +3999,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.79"
+version = "0.2.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
+checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
 dependencies = [
  "cfg-if 1.0.0",
  "wasm-bindgen-macro",
@@ -3974,13 +4009,13 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.79"
+version = "0.2.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
+checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f"
 dependencies = [
  "bumpalo",
- "lazy_static",
  "log",
+ "once_cell",
  "proc-macro2 1.0.39",
  "quote 1.0.15",
  "syn",
@@ -3989,9 +4024,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.79"
+version = "0.2.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
+checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602"
 dependencies = [
  "quote 1.0.15",
  "wasm-bindgen-macro-support",
@@ -3999,9 +4034,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.79"
+version = "0.2.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
+checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da"
 dependencies = [
  "proc-macro2 1.0.39",
  "quote 1.0.15",
@@ -4012,9 +4047,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.79"
+version = "0.2.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
+checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a"
 
 [[package]]
 name = "web-sys"
diff --git a/README.md b/README.md
index 39520e84..d4014ef4 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ $ create-rust-app <project_name>
     - One of the following frameworks: `actix-web`, `poem` or let us know which one you want to use!
     - Database migrations (using diesel.rs)
     - Sending mail
-    - PostgreSQL (but you can easily switch to another one!)
+    - PostgreSQL, SQLite 3.35+ support
     - ViteJS (blazing fast frontend compile speeds)
     - SSR templating with an option to include bundles that are automatically code-split
       - The `/views` folder contains all templates
diff --git a/create-rust-app/Cargo.toml b/create-rust-app/Cargo.toml
index a8adb431..10cfebf0 100644
--- a/create-rust-app/Cargo.toml
+++ b/create-rust-app/Cargo.toml
@@ -15,13 +15,13 @@ categories = ["command-line-utilities", "development-tools", "web-programming",
 ## COMMON / DEFAULT - required dependencies
 ##
 dotenv = "0.15.0"
-serde_json = "1.0.81"
+serde_json = "1.0.83"
 lettre = "0.9.6"
 lettre_email = "0.9.4"
-tera = { version="1.15.0" }
+tera = { version="1.17.0" }
 lazy_static = { version="1.4.0" }
-serde = { version = "1.0.137", features = ["derive"] }
-diesel = { version="2.0.0-rc.1", default-features = false, features = ["postgres", "uuid", "r2d2", "chrono"] } # plugin_dev, plugin_auth
+serde = { version = "1.0.143", features = ["derive"] }
+diesel = { version="2.0.0-rc.1", default-features = false, features = ["uuid", "r2d2", "chrono", "returning_clauses_for_sqlite_3_35"] } # plugin_dev, plugin_auth
 
 ##
 ## PLUGINS
@@ -30,8 +30,8 @@ diesel = { version="2.0.0-rc.1", default-features = false, features = ["postgres
 # plugin_auth
 argonautica = { optional=true, version="0.2.0" }
 jsonwebtoken = { optional=true, version="7.2.0" }
-tsync = { optional=true, version="1.2.1" }
-chrono = { optional=true, version = "0.4.19", features = ["serde"] }
+tsync = { optional=true, version="1.3.0" }
+chrono = { optional=true, version = "0.4.22", features = ["serde"] }
 
 # plugin_dev
 diesel_migrations = { optional=true, version="2.0.0-rc.1" }
@@ -74,7 +74,7 @@ mime_guess = { optional=true, version="2.0.4" } # backend_poem, plugin_storage
 anyhow = { optional=true, version="1.0.57" } # backend_poem, plugin_auth
 
 [features]
-default = []
+default = [] # ["INTERNAL_DEV_DO_NOT_USE"]
 plugin_dev = ["diesel_migrations"]
 plugin_container = []
 plugin_auth = ["anyhow", "argonautica", "jsonwebtoken", "chrono", "tsync"]
@@ -82,3 +82,6 @@ plugin_storage = [ "aws-config", "aws-types", "aws-endpoint", "aws-sdk-s3", "tok
 plugin_graphql = []
 backend_poem = ["poem", "anyhow", "mime_guess"]
 backend_actix-web = ["actix-web", "actix-http", "actix-files", "actix-multipart", "actix-web-httpauth","derive_more", "futures", "env_logger"]
+database_sqlite = ["diesel/sqlite"]
+database_postgres = ["diesel/postgres"]
+INTERNAL_DEV_DO_NOT_USE = ["plugin_auth", "plugin_container", "plugin_dev", "plugin_graphql", "plugin_storage", "backend_actix-web", "database_sqlite"]
\ No newline at end of file
diff --git a/create-rust-app/src/auth/controller.rs b/create-rust-app/src/auth/controller.rs
index 9c3287ef..0fd9ca22 100644
--- a/create-rust-app/src/auth/controller.rs
+++ b/create-rust-app/src/auth/controller.rs
@@ -1,9 +1,12 @@
-use jsonwebtoken::{decode, DecodingKey, encode, EncodingKey, Header, Validation};
+use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
 
+use crate::auth::{
+    mail, AccessTokenClaims, Auth, PaginationParams, Permission, Role, User, UserChangeset,
+    UserSession, UserSessionChangeset, UserSessionJson, UserSessionResponse, ID,
+};
 use crate::{Database, Mailer};
-use crate::auth::{AccessTokenClaims, Auth, ID, mail, PaginationParams, Permission, Role, User, UserChangeset, UserSession, UserSessionChangeset, UserSessionJson, UserSessionResponse};
 
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
 
 pub const COOKIE_NAME: &'static str = "refresh_token";
 
@@ -16,7 +19,7 @@ pub struct LoginInput {
     email: String,
     password: String,
     device: Option<String>,
-    ttl: Option<Seconds>
+    ttl: Option<Seconds>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -69,7 +72,11 @@ pub struct ResetInput {
 }
 
 /// /sessions
-pub fn get_sessions(db: &Database, auth: &Auth, info: &PaginationParams) -> Result<UserSessionResponse, (StatusCode, Message)> {
+pub fn get_sessions(
+    db: &Database,
+    auth: &Auth,
+    info: &PaginationParams,
+) -> Result<UserSessionResponse, (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     let sessions = UserSession::read_all(&mut db, &info, auth.user_id);
@@ -86,6 +93,7 @@ pub fn get_sessions(db: &Database, auth: &Auth, info: &PaginationParams) -> Resu
             id: session.id,
             device: session.device,
             created_at: session.created_at,
+            #[cfg(not(feature = "database_sqlite"))]
             updated_at: session.updated_at,
         };
 
@@ -98,7 +106,12 @@ pub fn get_sessions(db: &Database, auth: &Auth, info: &PaginationParams) -> Resu
     }
 
     let num_sessions = num_sessions.unwrap();
-    let num_pages = (num_sessions / info.page_size) + (if num_sessions % info.page_size != 0 { 1 } else { 0 });
+    let num_pages = (num_sessions / info.page_size)
+        + (if num_sessions % info.page_size != 0 {
+            1
+        } else {
+            0
+        });
 
     let resp = UserSessionResponse {
         sessions: sessions_json,
@@ -109,7 +122,11 @@ pub fn get_sessions(db: &Database, auth: &Auth, info: &PaginationParams) -> Resu
 }
 
 /// /sessions/{id}
-pub fn destroy_session(db: &Database, auth: &Auth, item_id: ID) -> Result<(), (StatusCode, Message)> {
+pub fn destroy_session(
+    db: &Database,
+    auth: &Auth,
+    item_id: ID,
+) -> Result<(), (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     let user_session = UserSession::read(&mut db, item_id);
@@ -149,7 +166,10 @@ type RefreshToken = String;
 /// Returns a tuple;
 /// - the access token should be sent to the user in the body, and,
 /// - the reset token should be sent as a secure, http-only, and same_site=strict cookie.
-pub fn login(db: &Database, item: &LoginInput) -> Result<(AccessToken, RefreshToken), (StatusCode, Message)> {
+pub fn login(
+    db: &Database,
+    item: &LoginInput,
+) -> Result<(AccessToken, RefreshToken), (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     // verify device
@@ -202,14 +222,12 @@ pub fn login(db: &Database, item: &LoginInput) -> Result<(AccessToken, RefreshTo
     }
     let roles = roles.unwrap();
 
-    let access_token_duration = chrono::Duration::seconds(
-        if item.ttl.is_some() {
-            std::cmp::max(item.ttl.unwrap(), 1)
-        } else {
-            /* 15 minutes */
-            15 * 60
-        }
-    );
+    let access_token_duration = chrono::Duration::seconds(if item.ttl.is_some() {
+        std::cmp::max(item.ttl.unwrap(), 1)
+    } else {
+        /* 15 minutes */
+        15 * 60
+    });
 
     let access_token_claims = AccessTokenClaims {
         exp: (chrono::Utc::now() + access_token_duration).timestamp() as usize,
@@ -229,19 +247,24 @@ pub fn login(db: &Database, item: &LoginInput) -> Result<(AccessToken, RefreshTo
         &Header::default(),
         &access_token_claims,
         &EncodingKey::from_secret(std::env::var("SECRET_KEY").unwrap().as_ref()),
-    ).unwrap();
+    )
+    .unwrap();
 
     let refresh_token = encode(
         &Header::default(),
         &refresh_token_claims,
         &EncodingKey::from_secret(std::env::var("SECRET_KEY").unwrap().as_ref()),
-    ).unwrap();
-
-    let user_session = UserSession::create(&mut db, &UserSessionChangeset {
-        user_id: user.id,
-        refresh_token: refresh_token.clone(),
-        device,
-    });
+    )
+    .unwrap();
+
+    let user_session = UserSession::create(
+        &mut db,
+        &UserSessionChangeset {
+            user_id: user.id,
+            refresh_token: refresh_token.clone(),
+            device,
+        },
+    );
 
     if user_session.is_err() {
         return Err((500, "Could not create a session."));
@@ -256,7 +279,7 @@ pub fn logout(db: &Database, refresh_token: Option<&'_ str>) -> Result<(), (Stat
     let mut db = db.pool.get().unwrap();
 
     if refresh_token.is_none() {
-        return Err((401, "Invalid session."))
+        return Err((401, "Invalid session."));
     }
 
     let refresh_token = refresh_token.unwrap();
@@ -282,7 +305,10 @@ pub fn logout(db: &Database, refresh_token: Option<&'_ str>) -> Result<(), (Stat
 /// Returns a tuple;
 /// - the access token should be sent to the user in the body, and,
 /// - the reset token should be sent as a secure, http-only, and same_site=strict cookie.
-pub fn refresh(db: &Database, refresh_token_str: Option<&'_ str>) -> Result<(AccessToken, RefreshToken), (StatusCode, Message)> {
+pub fn refresh(
+    db: &Database,
+    refresh_token_str: Option<&'_ str>,
+) -> Result<(AccessToken, RefreshToken), (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     if refresh_token_str.is_none() {
@@ -303,7 +329,11 @@ pub fn refresh(db: &Database, refresh_token_str: Option<&'_ str>) -> Result<(Acc
 
     let refresh_token = refresh_token.unwrap();
 
-    if !refresh_token.claims.token_type.eq_ignore_ascii_case("refresh_token") {
+    if !refresh_token
+        .claims
+        .token_type
+        .eq_ignore_ascii_case("refresh_token")
+    {
         return Err((401, "Invalid token."));
     }
 
@@ -316,11 +346,15 @@ pub fn refresh(db: &Database, refresh_token_str: Option<&'_ str>) -> Result<(Acc
     let session = session.unwrap();
 
     let permissions = Permission::fetch_all(&mut db, session.user_id);
-    if permissions.is_err() { return Err((500, "An internal server error occurred.")); }
+    if permissions.is_err() {
+        return Err((500, "An internal server error occurred."));
+    }
     let permissions = permissions.unwrap();
 
     let roles = Role::fetch_all(&mut db, session.user_id);
-    if roles.is_err() { return Err((500, "An internal server error occurred.")); }
+    if roles.is_err() {
+        return Err((500, "An internal server error occurred."));
+    }
     let roles = roles.unwrap();
 
     let access_token_claims = AccessTokenClaims {
@@ -341,20 +375,26 @@ pub fn refresh(db: &Database, refresh_token_str: Option<&'_ str>) -> Result<(Acc
         &Header::default(),
         &access_token_claims,
         &EncodingKey::from_secret(std::env::var("SECRET_KEY").unwrap().as_ref()),
-    ).unwrap();
+    )
+    .unwrap();
 
     let refresh_token_str = encode(
         &Header::default(),
         &refresh_token_claims,
         &EncodingKey::from_secret(std::env::var("SECRET_KEY").unwrap().as_ref()),
-    ).unwrap();
+    )
+    .unwrap();
 
     // update session with the new refresh token
-    let session_update = UserSession::update(&mut db, session.id, &UserSessionChangeset {
-        user_id: session.user_id,
-        refresh_token: refresh_token_str.clone(),
-        device: session.device,
-    });
+    let session_update = UserSession::update(
+        &mut db,
+        session.id,
+        &UserSessionChangeset {
+            user_id: session.user_id,
+            refresh_token: refresh_token_str.clone(),
+            device: session.device,
+        },
+    );
 
     if session_update.is_err() {
         return Err((500, "Could not update the session."));
@@ -364,7 +404,11 @@ pub fn refresh(db: &Database, refresh_token_str: Option<&'_ str>) -> Result<(Acc
 }
 
 /// /register
-pub fn register(db: &Database, item: &RegisterInput, mailer: &Mailer) -> Result<(), (StatusCode, Message)> {
+pub fn register(
+    db: &Database,
+    item: &RegisterInput,
+    mailer: &Mailer,
+) -> Result<(), (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     let user = User::find_by_email(&mut db, (&item.email).to_string());
@@ -388,11 +432,15 @@ pub fn register(db: &Database, item: &RegisterInput, mailer: &Mailer) -> Result<
         .hash()
         .unwrap();
 
-    let user = User::create(&mut db, &UserChangeset {
-        activated: false,
-        email: item.email.clone(),
-        hash_password: hash,
-    }).unwrap();
+    let user = User::create(
+        &mut db,
+        &UserChangeset {
+            activated: false,
+            email: item.email.clone(),
+            hash_password: hash,
+        },
+    )
+    .unwrap();
 
     let registration_claims = RegistrationClaims {
         exp: (chrono::Utc::now() + chrono::Duration::days(30)).timestamp() as usize,
@@ -404,15 +452,27 @@ pub fn register(db: &Database, item: &RegisterInput, mailer: &Mailer) -> Result<
         &Header::default(),
         &registration_claims,
         &EncodingKey::from_secret(std::env::var("SECRET_KEY").unwrap().as_ref()),
-    ).unwrap();
-
-    mail::auth_register::send(&mailer, &user.email, &format!("http://localhost:3000/activate?token={token}", token = token));
+    )
+    .unwrap();
+
+    mail::auth_register::send(
+        &mailer,
+        &user.email,
+        &format!(
+            "http://localhost:3000/activate?token={token}",
+            token = token
+        ),
+    );
 
     Ok(())
 }
 
 /// /activate
-pub fn activate(db: &Database, item: &ActivationInput, mailer: &Mailer) -> Result<(), (StatusCode, Message)> {
+pub fn activate(
+    db: &Database,
+    item: &ActivationInput,
+    mailer: &Mailer,
+) -> Result<(), (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     let token = decode::<RegistrationClaims>(
@@ -427,7 +487,11 @@ pub fn activate(db: &Database, item: &ActivationInput, mailer: &Mailer) -> Resul
 
     let token = token.unwrap();
 
-    if !token.claims.token_type.eq_ignore_ascii_case("activation_token") {
+    if !token
+        .claims
+        .token_type
+        .eq_ignore_ascii_case("activation_token")
+    {
         return Err((401, "Invalid token."));
     }
 
@@ -443,11 +507,15 @@ pub fn activate(db: &Database, item: &ActivationInput, mailer: &Mailer) -> Resul
         return Err((200, "Already activated!"));
     }
 
-    let activated_user = User::update(&mut db, user.id, &UserChangeset {
-        activated: true,
-        email: user.email.clone(),
-        hash_password: user.hash_password,
-    });
+    let activated_user = User::update(
+        &mut db,
+        user.id,
+        &UserChangeset {
+            activated: true,
+            email: user.email.clone(),
+            hash_password: user.hash_password,
+        },
+    );
 
     if activated_user.is_err() {
         return Err((500, "Could not activate user."));
@@ -459,7 +527,11 @@ pub fn activate(db: &Database, item: &ActivationInput, mailer: &Mailer) -> Resul
 }
 
 /// /forgot
-pub fn forgot_password(db: &Database, item: &ForgotInput, mailer: &Mailer) -> Result<(), (StatusCode, Message)> {
+pub fn forgot_password(
+    db: &Database,
+    item: &ForgotInput,
+    mailer: &Mailer,
+) -> Result<(), (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     let user_result = User::find_by_email(&mut db, item.email.clone());
@@ -481,9 +553,13 @@ pub fn forgot_password(db: &Database, item: &ForgotInput, mailer: &Mailer) -> Re
             &Header::default(),
             &reset_token_claims,
             &EncodingKey::from_secret(std::env::var("SECRET_KEY").unwrap().as_ref()),
-        ).unwrap();
+        )
+        .unwrap();
 
-        let link = &format!("http://localhost:3000/reset?token={reset_token}", reset_token = reset_token);
+        let link = &format!(
+            "http://localhost:3000/reset?token={reset_token}",
+            reset_token = reset_token
+        );
         mail::auth_recover_existent_account::send(&mailer, &user.email, link);
     } else {
         let link = &format!("http://localhost:300/register");
@@ -494,7 +570,12 @@ pub fn forgot_password(db: &Database, item: &ForgotInput, mailer: &Mailer) -> Re
 }
 
 /// /change
-pub fn change_password(db: &Database, item: &ChangeInput, auth: &Auth, mailer: &Mailer) -> Result<(), (StatusCode, Message)> {
+pub fn change_password(
+    db: &Database,
+    item: &ChangeInput,
+    auth: &Auth,
+    mailer: &Mailer,
+) -> Result<(), (StatusCode, Message)> {
     if item.old_password.len() == 0 || item.new_password.len() == 0 {
         return Err((400, "Missing password"));
     }
@@ -542,11 +623,15 @@ pub fn change_password(db: &Database, item: &ChangeInput, auth: &Auth, mailer: &
         .hash()
         .unwrap();
 
-    let updated_user = User::update(&mut db, auth.user_id, &UserChangeset {
-        email: user.email.clone(),
-        hash_password: new_hash,
-        activated: user.activated,
-    });
+    let updated_user = User::update(
+        &mut db,
+        auth.user_id,
+        &UserChangeset {
+            email: user.email.clone(),
+            hash_password: new_hash,
+            activated: user.activated,
+        },
+    );
 
     if updated_user.is_err() {
         return Err((500, "Could not update password"));
@@ -558,11 +643,14 @@ pub fn change_password(db: &Database, item: &ChangeInput, auth: &Auth, mailer: &
 }
 
 /// /check
-pub fn check(_: &Auth) {
-}
+pub fn check(_: &Auth) {}
 
 /// reset
-pub fn reset_password(db: &Database, item: &ResetInput, mailer: &Mailer) -> Result<(), (StatusCode, Message)> {
+pub fn reset_password(
+    db: &Database,
+    item: &ResetInput,
+    mailer: &Mailer,
+) -> Result<(), (StatusCode, Message)> {
     let mut db = db.pool.get().unwrap();
 
     if item.new_password.len() == 0 {
@@ -607,11 +695,15 @@ pub fn reset_password(db: &Database, item: &ResetInput, mailer: &Mailer) -> Resu
         .hash()
         .unwrap();
 
-    let update = User::update(&mut db, user.id, &UserChangeset {
-        email: user.email.clone(),
-        hash_password: new_hash,
-        activated: user.activated,
-    });
+    let update = User::update(
+        &mut db,
+        user.id,
+        &UserChangeset {
+            email: user.email.clone(),
+            hash_password: new_hash,
+            activated: user.activated,
+        },
+    );
 
     if update.is_err() {
         return Err((500, "Could not update password"));
diff --git a/create-rust-app/src/auth/endpoints/service_actixweb.rs b/create-rust-app/src/auth/endpoints/service_actixweb.rs
index f1be5048..0818e62b 100644
--- a/create-rust-app/src/auth/endpoints/service_actixweb.rs
+++ b/create-rust-app/src/auth/endpoints/service_actixweb.rs
@@ -1,32 +1,61 @@
 extern crate argonautica;
 
 use actix_http::StatusCode;
-use actix_web::{delete, Error as AWError, get, post, Result, web};
-use actix_web::{HttpRequest, HttpResponse, web::{Data, Json, Path, Query}};
 use actix_web::cookie::{Cookie, SameSite};
+use actix_web::{delete, get, post, web, Error as AWError, Result};
+use actix_web::{
+    web::{Data, Json, Path, Query},
+    HttpRequest, HttpResponse,
+};
 use serde_json::json;
 
-use crate::auth::{Auth, controller, controller::{ActivationInput, ChangeInput, COOKIE_NAME, ForgotInput, LoginInput, RegisterInput, ResetInput}, ID, PaginationParams};
+use crate::auth::{
+    controller,
+    controller::{
+        ActivationInput, ChangeInput, ForgotInput, LoginInput, RegisterInput, ResetInput,
+        COOKIE_NAME,
+    },
+    Auth, PaginationParams, ID,
+};
 use crate::Database;
 use crate::Mailer;
 
 #[get("/sessions")]
-async fn sessions(db: Data<Database>, auth: Auth, Query(info): Query<PaginationParams>) -> Result<HttpResponse> {
-    let result = web::block(move || controller::get_sessions(db.into_inner().as_ref(), &auth, &info)).await?;
+async fn sessions(
+    db: Data<Database>,
+    auth: Auth,
+    Query(info): Query<PaginationParams>,
+) -> Result<HttpResponse> {
+    let result =
+        web::block(move || controller::get_sessions(db.into_inner().as_ref(), &auth, &info))
+            .await?;
 
     match result {
         Ok(sessions) => Ok(HttpResponse::Ok().json(sessions)),
-        Err((status_code, error_message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": error_message}).to_string()))
+        Err((status_code, error_message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": error_message }).to_string())),
     }
 }
 
 #[delete("/sessions/{id}")]
-async fn destroy_session(db: Data<Database>, item_id: Path<ID>, auth: Auth) -> Result<HttpResponse> {
-    let result = web::block(move || controller::destroy_session(&db, &auth, item_id.into_inner())).await?;
+async fn destroy_session(
+    db: Data<Database>,
+    item_id: Path<ID>,
+    auth: Auth,
+) -> Result<HttpResponse> {
+    let result =
+        web::block(move || controller::destroy_session(&db, &auth, item_id.into_inner())).await?;
 
     match result {
-        Ok(_) => Ok(HttpResponse::build(StatusCode::OK).body(json!({"message": "Deleted."}).to_string())),
-        Err((status_code, error_message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": error_message}).to_string()))
+        Ok(_) => Ok(
+            HttpResponse::build(StatusCode::OK).body(json!({"message": "Deleted."}).to_string())
+        ),
+        Err((status_code, error_message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": error_message }).to_string())),
     }
 }
 
@@ -35,8 +64,13 @@ async fn destroy_sessions(db: Data<Database>, auth: Auth) -> Result<HttpResponse
     let result = web::block(move || controller::destroy_sessions(&db, &auth)).await?;
 
     match result {
-        Ok(_) => Ok(HttpResponse::build(StatusCode::OK).body(json!({"message": "Deleted."}).to_string())),
-        Err((status_code, error_message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": error_message}).to_string()))
+        Ok(_) => Ok(
+            HttpResponse::build(StatusCode::OK).body(json!({"message": "Deleted."}).to_string())
+        ),
+        Err((status_code, error_message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": error_message }).to_string())),
     }
 }
 
@@ -46,23 +80,30 @@ async fn login(db: Data<Database>, Json(item): Json<LoginInput>) -> Result<HttpR
 
     match result {
         Ok((access_token, refresh_token)) => Ok(HttpResponse::build(StatusCode::OK)
-            .cookie(Cookie::build(COOKIE_NAME, refresh_token.clone())
-                .secure(true)
-                .http_only(true)
-                .same_site(SameSite::Strict)
-                .finish())
-            .body(json!({
-          "access_token": access_token
-        }).to_string())),
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+            .cookie(
+                Cookie::build(COOKIE_NAME, refresh_token.clone())
+                    .secure(true)
+                    .http_only(true)
+                    .same_site(SameSite::Strict)
+                    .finish(),
+            )
+            .body(json!({ "access_token": access_token }).to_string())),
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
 #[post("/logout")]
 async fn logout(db: Data<Database>, req: HttpRequest) -> Result<HttpResponse, AWError> {
-    let refresh_token = req.cookie(COOKIE_NAME).map(|cookie| String::from(cookie.value()));
+    let refresh_token = req
+        .cookie(COOKIE_NAME)
+        .map(|cookie| String::from(cookie.value()));
 
-    let result = web::block(move || controller::logout(&db, refresh_token.as_ref().map(|t| t.as_ref()))).await?;
+    let result =
+        web::block(move || controller::logout(&db, refresh_token.as_ref().map(|t| t.as_ref())))
+            .await?;
 
     match result {
         Ok(_) => {
@@ -71,67 +112,109 @@ async fn logout(db: Data<Database>, req: HttpRequest) -> Result<HttpResponse, AW
 
             Ok(HttpResponse::Ok().cookie(cookie).finish())
         }
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
 #[post("/refresh")]
 async fn refresh(db: Data<Database>, req: HttpRequest) -> Result<HttpResponse, AWError> {
-    let refresh_token = req.cookie(COOKIE_NAME).map(|cookie| String::from(cookie.value()));
+    let refresh_token = req
+        .cookie(COOKIE_NAME)
+        .map(|cookie| String::from(cookie.value()));
 
-    let result = web::block(move || controller::refresh(&db, refresh_token.as_ref().map(|t| t.as_ref()))).await?;
+    let result =
+        web::block(move || controller::refresh(&db, refresh_token.as_ref().map(|t| t.as_ref())))
+            .await?;
 
     match result {
         Ok((access_token, refresh_token)) => Ok(HttpResponse::build(StatusCode::OK)
-            .cookie(Cookie::build(COOKIE_NAME, refresh_token)
-                .secure(true)
-                .http_only(true)
-                .same_site(SameSite::Strict)
-                .finish())
-            .body(json!({
-          "access_token": access_token
-        }).to_string())),
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+            .cookie(
+                Cookie::build(COOKIE_NAME, refresh_token)
+                    .secure(true)
+                    .http_only(true)
+                    .same_site(SameSite::Strict)
+                    .finish(),
+            )
+            .body(json!({ "access_token": access_token }).to_string())),
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
 #[post("/register")]
-async fn register(db: Data<Database>, Json(item): Json<RegisterInput>, mailer: Data<Mailer>) -> Result<HttpResponse, AWError> {
+async fn register(
+    db: Data<Database>,
+    Json(item): Json<RegisterInput>,
+    mailer: Data<Mailer>,
+) -> Result<HttpResponse, AWError> {
     let result = controller::register(&db, &item, &mailer);
 
     match result {
-        Ok(()) => Ok(HttpResponse::build(StatusCode::OK).body("{ \"message\": \"Registered! Check your email to activate your account.\" }")),
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+        Ok(()) => Ok(HttpResponse::build(StatusCode::OK)
+            .body("{ \"message\": \"Registered! Check your email to activate your account.\" }")),
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
 #[get("/activate")]
-async fn activate(db: Data<Database>, Query(item): Query<ActivationInput>, mailer: Data<Mailer>) -> Result<HttpResponse, AWError> {
+async fn activate(
+    db: Data<Database>,
+    Query(item): Query<ActivationInput>,
+    mailer: Data<Mailer>,
+) -> Result<HttpResponse, AWError> {
     let result = controller::activate(&db, &item, &mailer);
 
     match result {
         Ok(()) => Ok(HttpResponse::build(StatusCode::OK).body("{ \"message\": \"Activated!\" }")),
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
 #[post("/forgot")]
-async fn forgot_password(db: Data<Database>, Json(item): Json<ForgotInput>, mailer: Data<Mailer>) -> Result<HttpResponse, AWError> {
+async fn forgot_password(
+    db: Data<Database>,
+    Json(item): Json<ForgotInput>,
+    mailer: Data<Mailer>,
+) -> Result<HttpResponse, AWError> {
     let result = controller::forgot_password(&db, &item, &mailer);
 
     match result {
-        Ok(()) => Ok(HttpResponse::build(StatusCode::OK).body("{ \"message\": \"Please check your email.\" }")),
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+        Ok(()) => Ok(HttpResponse::build(StatusCode::OK)
+            .body("{ \"message\": \"Please check your email.\" }")),
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
 #[post("/change")]
-async fn change_password(db: Data<Database>, Json(item): Json<ChangeInput>, auth: Auth, mailer: Data<Mailer>) -> Result<HttpResponse, AWError> {
+async fn change_password(
+    db: Data<Database>,
+    Json(item): Json<ChangeInput>,
+    auth: Auth,
+    mailer: Data<Mailer>,
+) -> Result<HttpResponse, AWError> {
     let result = controller::change_password(&db, &item, &auth, &mailer);
 
     match result {
-        Ok(()) => Ok(HttpResponse::build(StatusCode::OK).body(json!({"message": "Password changed."}).to_string())),
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+        Ok(()) => Ok(HttpResponse::build(StatusCode::OK)
+            .body(json!({"message": "Password changed."}).to_string())),
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
@@ -142,12 +225,20 @@ async fn check(auth: Auth) -> HttpResponse {
 }
 
 #[post("/reset")]
-async fn reset_password(db: Data<Database>, Json(item): Json<ResetInput>, mailer: Data<Mailer>) -> Result<HttpResponse, AWError> {
+async fn reset_password(
+    db: Data<Database>,
+    Json(item): Json<ResetInput>,
+    mailer: Data<Mailer>,
+) -> Result<HttpResponse, AWError> {
     let result = controller::reset_password(&db, &item, &mailer);
 
     match result {
-        Ok(()) => Ok(HttpResponse::build(StatusCode::OK).body(json!({"message": "Password reset"}).to_string())),
-        Err((status_code, message)) => Ok(HttpResponse::build(StatusCode::from_u16(status_code as u16).unwrap()).body(json!({"message": message}).to_string()))
+        Ok(()) => Ok(HttpResponse::build(StatusCode::OK)
+            .body(json!({"message": "Password reset"}).to_string())),
+        Err((status_code, message)) => Ok(HttpResponse::build(
+            StatusCode::from_u16(status_code as u16).unwrap(),
+        )
+        .body(json!({ "message": message }).to_string())),
     }
 }
 
diff --git a/create-rust-app/src/auth/endpoints/service_poem.rs b/create-rust-app/src/auth/endpoints/service_poem.rs
index 61bc5875..7dd006fa 100644
--- a/create-rust-app/src/auth/endpoints/service_poem.rs
+++ b/create-rust-app/src/auth/endpoints/service_poem.rs
@@ -1,21 +1,39 @@
-use poem::{delete, Error, get, handler, http::StatusCode, IntoResponse, post, Response, Result, Route, web::{cookie::{Cookie, CookieJar, SameSite}, Data, Json, Path, Query}};
+use poem::{
+    delete, get, handler,
+    http::StatusCode,
+    post,
+    web::{
+        cookie::{Cookie, CookieJar, SameSite},
+        Data, Json, Path, Query,
+    },
+    Error, IntoResponse, Response, Result, Route,
+};
 use serde_json::json;
 
+use crate::auth::controller::{
+    ActivationInput, ChangeInput, ForgotInput, LoginInput, RegisterInput, ResetInput, COOKIE_NAME,
+};
+use crate::auth::{controller, Auth, PaginationParams, ID};
 use crate::{Database, Mailer};
-use crate::auth::{Auth, controller, ID, PaginationParams};
-use crate::auth::controller::{ActivationInput, ChangeInput, COOKIE_NAME, ForgotInput, LoginInput, RegisterInput, ResetInput};
 
 fn error_response(status_code: i32, message: &'static str) -> Error {
-    Error::from_string(json!({"message": message}).to_string(), StatusCode::from_u16(status_code as u16).unwrap())
+    Error::from_string(
+        json!({ "message": message }).to_string(),
+        StatusCode::from_u16(status_code as u16).unwrap(),
+    )
 }
 
 #[handler]
-async fn sessions(db: Data<&Database>, auth: Auth, Query(info): Query<PaginationParams>) -> Result<impl IntoResponse> {
+async fn sessions(
+    db: Data<&Database>,
+    auth: Auth,
+    Query(info): Query<PaginationParams>,
+) -> Result<impl IntoResponse> {
     let result = controller::get_sessions(db.0, &auth, &info);
 
     match result {
         Ok(sessions) => Ok(Json(sessions)),
-        Err((status_code, message)) => Err(error_response(status_code, message))
+        Err((status_code, message)) => Err(error_response(status_code, message)),
     }
 }
 
@@ -25,22 +43,30 @@ async fn destroy_sessions(db: Data<&Database>, auth: Auth) -> Result<impl IntoRe
 
     match result {
         Ok(_) => Ok(Response::builder().status(StatusCode::OK).finish()),
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
-async fn destroy_session(db: Data<&Database>, Path(item_id): Path<ID>, auth: Auth) -> Result<impl IntoResponse> {
+async fn destroy_session(
+    db: Data<&Database>,
+    Path(item_id): Path<ID>,
+    auth: Auth,
+) -> Result<impl IntoResponse> {
     let result = controller::destroy_session(db.0, &auth, item_id);
 
     match result {
         Ok(_) => Ok(Response::builder().status(StatusCode::OK).finish()),
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
-async fn login(db: Data<&Database>, Json(item): Json<LoginInput>, cookie_jar: &CookieJar) -> Result<impl IntoResponse> {
+async fn login(
+    db: Data<&Database>,
+    Json(item): Json<LoginInput>,
+    cookie_jar: &CookieJar,
+) -> Result<impl IntoResponse> {
     let result = controller::login(db.0, &item);
 
     match result {
@@ -56,13 +82,15 @@ async fn login(db: Data<&Database>, Json(item): Json<LoginInput>, cookie_jar: &C
 
             Ok(response)
         }
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
 async fn logout(db: Data<&Database>, cookie_jar: &CookieJar) -> Result<impl IntoResponse> {
-    let refresh_token = cookie_jar.get(COOKIE_NAME).map(|cookie| String::from(cookie.value_str()));
+    let refresh_token = cookie_jar
+        .get(COOKIE_NAME)
+        .map(|cookie| String::from(cookie.value_str()));
 
     let result = controller::logout(db.0, refresh_token.as_ref().map(|t| t.as_str()));
 
@@ -75,13 +103,15 @@ async fn logout(db: Data<&Database>, cookie_jar: &CookieJar) -> Result<impl Into
 
             Ok(Response::builder().status(StatusCode::OK).finish())
         }
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
 async fn refresh(db: Data<&Database>, cookie_jar: &CookieJar) -> Result<impl IntoResponse> {
-    let refresh_token = cookie_jar.get(COOKIE_NAME).map(|cookie| String::from(cookie.value_str()));
+    let refresh_token = cookie_jar
+        .get(COOKIE_NAME)
+        .map(|cookie| String::from(cookie.value_str()));
 
     let result = controller::refresh(db.0, refresh_token.as_ref().map(|t| t.as_str()));
 
@@ -97,24 +127,32 @@ async fn refresh(db: Data<&Database>, cookie_jar: &CookieJar) -> Result<impl Int
                 .status(StatusCode::OK)
                 .body(json!({ "access_token": access_token }).to_string()))
         }
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
-async fn register(db: Data<&Database>, Json(item): Json<RegisterInput>, mailer: Data<&Mailer>) -> Result<impl IntoResponse> {
+async fn register(
+    db: Data<&Database>,
+    Json(item): Json<RegisterInput>,
+    mailer: Data<&Mailer>,
+) -> Result<impl IntoResponse> {
     let result = controller::register(db.0, &item, mailer.0);
 
     match result {
         Ok(_) => Ok(Response::builder()
             .status(StatusCode::OK)
             .body("{ \"message\": \"Registered! Check your email to activate your account.\" }")),
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
-async fn activate(db: Data<&Database>, Query(item): Query<ActivationInput>, mailer: Data<&Mailer>) -> Result<impl IntoResponse> {
+async fn activate(
+    db: Data<&Database>,
+    Query(item): Query<ActivationInput>,
+    mailer: Data<&Mailer>,
+) -> Result<impl IntoResponse> {
     let result = controller::activate(db.0, &item, mailer.0);
 
     match result {
@@ -122,39 +160,56 @@ async fn activate(db: Data<&Database>, Query(item): Query<ActivationInput>, mail
             .status(StatusCode::OK)
             .body("{ \"message\": \"Activated!\" }")),
 
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
-async fn forgot_password(db: Data<&Database>, Json(item): Json<ForgotInput>, mailer: Data<&Mailer>) -> Result<impl IntoResponse> {
+async fn forgot_password(
+    db: Data<&Database>,
+    Json(item): Json<ForgotInput>,
+    mailer: Data<&Mailer>,
+) -> Result<impl IntoResponse> {
     let result = controller::forgot_password(db.0, &item, mailer.0);
 
     match result {
         Ok(_) => Ok(Response::builder()
             .status(StatusCode::OK)
             .body("{ \"message\": \"Please check your email.\" }")),
-        Err((s, m)) => Err(error_response(s, m))
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
-async fn change_password(db: Data<&Database>, Json(item): Json<ChangeInput>, auth: Auth, mailer: Data<&Mailer>) -> Result<impl IntoResponse> {
+async fn change_password(
+    db: Data<&Database>,
+    Json(item): Json<ChangeInput>,
+    auth: Auth,
+    mailer: Data<&Mailer>,
+) -> Result<impl IntoResponse> {
     let result = controller::change_password(db.0, &item, &auth, mailer.0);
 
     match result {
-        Ok(_) => Ok(Response::builder().status(StatusCode::OK).body(json!({"message": "Password changed"}).to_string())),
-        Err((s, m)) => Err(error_response(s, m))
+        Ok(_) => Ok(Response::builder()
+            .status(StatusCode::OK)
+            .body(json!({"message": "Password changed"}).to_string())),
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
 #[handler]
-async fn reset_password(db: Data<&Database>, Json(item): Json<ResetInput>, mailer: Data<&Mailer>) -> Result<impl IntoResponse> {
+async fn reset_password(
+    db: Data<&Database>,
+    Json(item): Json<ResetInput>,
+    mailer: Data<&Mailer>,
+) -> Result<impl IntoResponse> {
     let result = controller::reset_password(db.0, &item, mailer.0);
 
     match result {
-        Ok(_) => Ok(Response::builder().status(StatusCode::OK).body(json!({"message": "Password reset"}).to_string())),
-        Err((s, m)) => Err(error_response(s, m))
+        Ok(_) => Ok(Response::builder()
+            .status(StatusCode::OK)
+            .body(json!({"message": "Password reset"}).to_string())),
+        Err((s, m)) => Err(error_response(s, m)),
     }
 }
 
diff --git a/create-rust-app/src/auth/extractors/auth_actixweb.rs b/create-rust-app/src/auth/extractors/auth_actixweb.rs
index 723c4d9d..e80f9b9a 100644
--- a/create-rust-app/src/auth/extractors/auth_actixweb.rs
+++ b/create-rust-app/src/auth/extractors/auth_actixweb.rs
@@ -1,5 +1,5 @@
-use std::collections::HashSet;
-use crate::auth::{AccessTokenClaims, ID, permissions::Permission};
+use crate::auth::{permissions::Permission, AccessTokenClaims, ID};
+use actix_http::header::HeaderValue;
 use actix_web::dev::Payload;
 use actix_web::error::ResponseError;
 use actix_web::http::StatusCode;
@@ -10,8 +10,8 @@ use jsonwebtoken::decode;
 use jsonwebtoken::DecodingKey;
 use jsonwebtoken::Validation;
 use serde_json::json;
+use std::collections::HashSet;
 use std::iter::FromIterator;
-use actix_http::header::HeaderValue;
 
 #[derive(Debug, Clone)]
 pub struct Auth {
@@ -22,7 +22,10 @@ pub struct Auth {
 
 impl Auth {
     pub fn has_permission(&self, permission: String) -> bool {
-        self.permissions.contains(&Permission { permission: permission.to_string(), from_role: String::new() })
+        self.permissions.contains(&Permission {
+            permission: permission.to_string(),
+            from_role: String::new(),
+        })
     }
 
     pub fn has_all_permissions(&self, perms: Vec<String>) -> bool {
@@ -56,9 +59,12 @@ impl ResponseError for AuthError {
     fn error_response(&self) -> HttpResponse {
         // HttpResponse::Unauthorized().json(self.reason.as_str())
         // println!("error_response");
-        HttpResponse::build(StatusCode::UNAUTHORIZED).body(json!({
-          "message": self.reason.as_str()
-        }).to_string())
+        HttpResponse::build(StatusCode::UNAUTHORIZED).body(
+            json!({
+              "message": self.reason.as_str()
+            })
+            .to_string(),
+        )
     }
 
     fn status_code(&self) -> StatusCode {
@@ -106,7 +112,8 @@ impl FromRequest for Auth {
         }
 
         let user_id = access_token.claims.sub;
-        let permissions: HashSet<Permission> = HashSet::from_iter(access_token.claims.permissions.iter().cloned());
+        let permissions: HashSet<Permission> =
+            HashSet::from_iter(access_token.claims.permissions.iter().cloned());
         let roles: HashSet<String> = HashSet::from_iter(access_token.claims.roles.iter().cloned());
 
         return ready(Ok(Auth {
diff --git a/create-rust-app/src/auth/extractors/auth_poem.rs b/create-rust-app/src/auth/extractors/auth_poem.rs
index 11a8bf56..e34af795 100644
--- a/create-rust-app/src/auth/extractors/auth_poem.rs
+++ b/create-rust-app/src/auth/extractors/auth_poem.rs
@@ -1,5 +1,8 @@
+use poem::{
+    async_trait, http::HeaderValue, http::StatusCode, Error, FromRequest, Request, RequestBody,
+    Result,
+};
 use std::collections::HashSet;
-use poem::{async_trait, http::HeaderValue, http::StatusCode, Error, FromRequest, Request, RequestBody, Result};
 
 use crate::auth::{permissions::Permission, AccessTokenClaims, ID};
 use jsonwebtoken::decode;
@@ -16,7 +19,10 @@ pub struct Auth {
 
 impl Auth {
     pub fn has_permission(&self, permission: String) -> bool {
-        self.permissions.contains(&Permission { permission: permission.to_string(), from_role: String::new() })
+        self.permissions.contains(&Permission {
+            permission: permission.to_string(),
+            from_role: String::new(),
+        })
     }
 
     pub fn has_all_permissions(&self, perms: Vec<String>) -> bool {
@@ -81,7 +87,8 @@ impl<'a> FromRequest<'a> for Auth {
         }
 
         let user_id = access_token.claims.sub;
-        let permissions: HashSet<Permission> = HashSet::from_iter(access_token.claims.permissions.iter().cloned());
+        let permissions: HashSet<Permission> =
+            HashSet::from_iter(access_token.claims.permissions.iter().cloned());
         let roles: HashSet<String> = HashSet::from_iter(access_token.claims.roles.iter().cloned());
 
         return Ok(Auth {
diff --git a/create-rust-app/src/auth/extractors/mod.rs b/create-rust-app/src/auth/extractors/mod.rs
index 18f50cf0..1f244c76 100644
--- a/create-rust-app/src/auth/extractors/mod.rs
+++ b/create-rust-app/src/auth/extractors/mod.rs
@@ -6,4 +6,4 @@ pub use auth_actixweb::Auth;
 #[cfg(feature = "backend_poem")]
 mod auth_poem;
 #[cfg(feature = "backend_poem")]
-pub use auth_poem::Auth;
\ No newline at end of file
+pub use auth_poem::Auth;
diff --git a/create-rust-app/src/auth/mod.rs b/create-rust-app/src/auth/mod.rs
index b865bce3..d3556808 100644
--- a/create-rust-app/src/auth/mod.rs
+++ b/create-rust-app/src/auth/mod.rs
@@ -1,5 +1,5 @@
 extern crate argonautica;
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
 
 // Auth guard / extractor
 mod extractors;
@@ -16,15 +16,21 @@ mod schema;
 mod user;
 mod user_session;
 
+pub use permissions::{
+    Permission, Role, RolePermission, RolePermissionChangeset, UserPermission,
+    UserPermissionChangeset,
+};
 pub use user::{User, UserChangeset};
 pub use user_session::{UserSession, UserSessionChangeset};
-pub use permissions::{Role, Permission, UserPermission, UserPermissionChangeset, RolePermission, RolePermissionChangeset};
 
 #[tsync::tsync]
 type ID = i32;
 
 #[tsync::tsync]
+#[cfg(not(feature = "database_sqlite"))]
 type UTC = chrono::DateTime<chrono::Utc>;
+#[cfg(feature = "database_sqlite")]
+type UTC = chrono::NaiveDateTime;
 
 #[tsync::tsync]
 #[derive(Deserialize)]
@@ -43,6 +49,7 @@ pub struct UserSessionJson {
     pub id: ID,
     pub device: Option<String>,
     pub created_at: UTC,
+    #[cfg(not(feature = "database_sqlite"))]
     pub updated_at: UTC,
 }
 
@@ -50,7 +57,7 @@ pub struct UserSessionJson {
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct UserSessionResponse {
     pub sessions: Vec<UserSessionJson>,
-    pub num_pages: i64
+    pub num_pages: i64,
 }
 
 #[tsync::tsync]
@@ -60,5 +67,5 @@ pub struct AccessTokenClaims {
     pub sub: ID,
     pub token_type: String,
     pub roles: Vec<String>,
-    pub permissions: Vec<Permission>
+    pub permissions: Vec<Permission>,
 }
diff --git a/create-rust-app/src/auth/permissions/mod.rs b/create-rust-app/src/auth/permissions/mod.rs
index 357dabf5..57a2c783 100644
--- a/create-rust-app/src/auth/permissions/mod.rs
+++ b/create-rust-app/src/auth/permissions/mod.rs
@@ -2,9 +2,9 @@ mod role_permission;
 mod user_permission;
 mod user_role;
 
+pub use role_permission::{RolePermission, RolePermissionChangeset};
 use std::hash::{Hash, Hasher};
 pub use user_permission::{UserPermission, UserPermissionChangeset};
-pub use role_permission::{RolePermission, RolePermissionChangeset};
 pub use user_role::{UserRole, UserRoleChangeset};
 
 use crate::database::Connection;
@@ -23,7 +23,7 @@ pub struct Role;
 #[derive(Debug, Serialize, Deserialize, QueryableByName, Clone)]
 struct RoleQueryRow {
     #[diesel(sql_type=Text)]
-    role: String
+    role: String,
 }
 
 impl Role {
@@ -42,10 +42,13 @@ impl Role {
     pub fn assign_many(db: &mut Connection, user_id: ID, roles: Vec<String>) -> Result<bool> {
         let assigned = UserRole::create_many(
             db,
-            roles.into_iter().map(|r| UserRoleChangeset {
-                user_id: user_id,
-                role: r,
-            }).collect::<Vec<_>>(),
+            roles
+                .into_iter()
+                .map(|r| UserRoleChangeset {
+                    user_id: user_id,
+                    role: r,
+                })
+                .collect::<Vec<_>>(),
         );
 
         Ok(assigned.is_ok())
@@ -64,17 +67,13 @@ impl Role {
     }
 
     pub fn fetch_all(db: &mut Connection, user_id: ID) -> Result<Vec<String>> {
-        let roles = sql_query(
-            "SELECT role FROM user_roles WHERE user_id = $1"
-        );
+        let roles = sql_query("SELECT role FROM user_roles WHERE user_id = $1");
 
         let roles = roles
             .bind::<Integer, _>(user_id)
             .get_results::<RoleQueryRow>(db)?;
 
-        let roles = roles.into_iter()
-            .map(|r| r.role)
-            .collect();
+        let roles = roles.into_iter().map(|r| r.role).collect();
 
         Ok(roles)
     }
@@ -103,7 +102,6 @@ impl PartialEq for Permission {
 }
 impl Eq for Permission {}
 
-
 impl Permission {
     // pub fn is_granted_to_user(db: &mut Connection, user_id: ID, permission: String) -> Result<bool> {
     //   let permissions = Permission::for_user(&db, user_id)?;
@@ -136,25 +134,39 @@ impl Permission {
         Ok(granted.is_ok())
     }
 
-    pub fn grant_many_to_role(db: &mut Connection, role: String, permissions: Vec<String>) -> Result<bool> {
+    pub fn grant_many_to_role(
+        db: &mut Connection,
+        role: String,
+        permissions: Vec<String>,
+    ) -> Result<bool> {
         let granted = RolePermission::create_many(
             db,
-            permissions.into_iter().map(|permission| RolePermissionChangeset {
-                permission,
-                role: role.clone(),
-            }).collect::<Vec<_>>(),
+            permissions
+                .into_iter()
+                .map(|permission| RolePermissionChangeset {
+                    permission,
+                    role: role.clone(),
+                })
+                .collect::<Vec<_>>(),
         );
 
         Ok(granted.is_ok())
     }
 
-    pub fn grant_many_to_user(db: &mut Connection, user_id: i32, permissions: Vec<String>) -> Result<bool> {
+    pub fn grant_many_to_user(
+        db: &mut Connection,
+        user_id: i32,
+        permissions: Vec<String>,
+    ) -> Result<bool> {
         let granted = UserPermission::create_many(
             db,
-            permissions.into_iter().map(|permission| UserPermissionChangeset {
-                permission,
-                user_id,
-            }).collect::<Vec<_>>(),
+            permissions
+                .into_iter()
+                .map(|permission| UserPermissionChangeset {
+                    permission,
+                    user_id,
+                })
+                .collect::<Vec<_>>(),
         );
 
         Ok(granted.is_ok())
@@ -172,13 +184,21 @@ impl Permission {
         Ok(deleted.is_ok())
     }
 
-    pub fn revoke_many_from_user(db: &mut Connection, user_id: ID, permissions: Vec<String>) -> Result<bool> {
+    pub fn revoke_many_from_user(
+        db: &mut Connection,
+        user_id: ID,
+        permissions: Vec<String>,
+    ) -> Result<bool> {
         let deleted = UserPermission::delete_many(db, user_id, permissions);
 
         Ok(deleted.is_ok())
     }
 
-    pub fn revoke_many_from_role(db: &mut Connection, role: String, permissions: Vec<String>) -> Result<bool> {
+    pub fn revoke_many_from_role(
+        db: &mut Connection,
+        role: String,
+        permissions: Vec<String>,
+    ) -> Result<bool> {
         let deleted = RolePermission::delete_many(db, role, permissions);
 
         Ok(deleted.is_ok())
diff --git a/create-rust-app/src/auth/permissions/role_permission.rs b/create-rust-app/src/auth/permissions/role_permission.rs
index 7296fa5a..24234c30 100644
--- a/create-rust-app/src/auth/permissions/role_permission.rs
+++ b/create-rust-app/src/auth/permissions/role_permission.rs
@@ -1,14 +1,12 @@
-use crate::diesel::*;
-use crate::auth::schema::*;
+use serde::{Deserialize, Serialize};
 
-use crate::auth::UTC;
+use crate::auth::{UTC, schema::*};
 use crate::database::Connection;
-use diesel::QueryResult;
-use serde::{Deserialize, Serialize};
+use crate::diesel::*;
 
 #[tsync::tsync]
 #[derive(Debug, Serialize, Deserialize, Clone, Queryable, Insertable, AsChangeset)]
-#[diesel(table_name=role_permissions)]
+#[diesel(table_name = role_permissions)]
 pub struct RolePermission {
     /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
     Add columns here in the same order as the schema
@@ -19,7 +17,7 @@ pub struct RolePermission {
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, Insertable, AsChangeset)]
-#[diesel(table_name=role_permissions)]
+#[diesel(table_name = role_permissions)]
 pub struct RolePermissionChangeset {
     /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
     Add columns here in the same order as the schema
@@ -39,7 +37,23 @@ impl RolePermission {
             .get_result::<RolePermission>(db)
     }
 
-    pub fn create_many(db: &mut Connection, items: Vec<RolePermissionChangeset>) -> QueryResult<Vec<Self>> {
+    #[cfg(feature = "database_sqlite")]
+    pub fn create_many(
+        db: &mut Connection,
+        items: Vec<RolePermissionChangeset>,
+    ) -> QueryResult<usize> {
+        use crate::auth::schema::role_permissions::dsl::*;
+
+        insert_into(role_permissions)
+            .values(items)
+            .execute(db)
+    }
+
+    #[cfg(not(feature = "database_sqlite"))]
+    pub fn create_many(
+        db: &mut Connection,
+        items: Vec<RolePermissionChangeset>,
+    ) -> QueryResult<Vec<Self>> {
         use crate::auth::schema::role_permissions::dsl::*;
 
         insert_into(role_permissions)
@@ -47,7 +61,11 @@ impl RolePermission {
             .get_results::<RolePermission>(db)
     }
 
-    pub fn read(db: &mut Connection, item_role: String, item_permission: String) -> QueryResult<Self> {
+    pub fn read(
+        db: &mut Connection,
+        item_role: String,
+        item_permission: String,
+    ) -> QueryResult<Self> {
         use crate::auth::schema::role_permissions::dsl::*;
 
         role_permissions
@@ -95,8 +113,6 @@ impl RolePermission {
     pub fn delete_all(db: &mut Connection, item_role: &str) -> QueryResult<usize> {
         use crate::auth::schema::role_permissions::dsl::*;
 
-        diesel::delete(
-            role_permissions.filter(role.eq(item_role)),
-        ).execute(db)
+        diesel::delete(role_permissions.filter(role.eq(item_role))).execute(db)
     }
 }
diff --git a/create-rust-app/src/auth/permissions/user_permission.rs b/create-rust-app/src/auth/permissions/user_permission.rs
index a5a45ade..e40feb51 100644
--- a/create-rust-app/src/auth/permissions/user_permission.rs
+++ b/create-rust-app/src/auth/permissions/user_permission.rs
@@ -1,15 +1,17 @@
 use diesel::QueryResult;
 use serde::{Deserialize, Serialize};
 
+use crate::auth::schema::*;
+use crate::diesel::*;
 use crate::{
-    auth::{ID, user::User, UTC},
+    auth::{user::User, ID, UTC},
     database::Connection,
 };
-use crate::auth::schema::*;
-use crate::diesel::*;
 
 #[tsync::tsync]
-#[derive(Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Associations, AsChangeset)]
+#[derive(
+    Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Associations, AsChangeset,
+)]
 #[diesel(table_name=user_permissions,belongs_to(User))]
 pub struct UserPermission {
     /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -41,7 +43,23 @@ impl UserPermission {
             .get_result::<UserPermission>(db)
     }
 
-    pub fn create_many(db: &mut Connection, items: Vec<UserPermissionChangeset>) -> QueryResult<Self> {
+    #[cfg(feature="database_sqlite")]
+    pub fn create_many(
+        db: &mut Connection,
+        items: Vec<UserPermissionChangeset>,
+    ) -> QueryResult<usize> {
+        use crate::auth::schema::user_permissions::dsl::*;
+
+        insert_into(user_permissions)
+            .values(items)
+            .execute(db)
+    }
+
+    #[cfg(not(feature="database_sqlite"))]
+    pub fn create_many(
+        db: &mut Connection,
+        items: Vec<UserPermissionChangeset>,
+    ) -> QueryResult<Self> {
         use crate::auth::schema::user_permissions::dsl::*;
 
         insert_into(user_permissions)
@@ -49,7 +67,11 @@ impl UserPermission {
             .get_result::<UserPermission>(db)
     }
 
-    pub fn read(db: &mut Connection, item_user_id: ID, item_permission: String) -> QueryResult<Self> {
+    pub fn read(
+        db: &mut Connection,
+        item_user_id: ID,
+        item_permission: String,
+    ) -> QueryResult<Self> {
         use crate::auth::schema::user_permissions::dsl::*;
 
         user_permissions
@@ -74,9 +96,9 @@ impl UserPermission {
         use crate::auth::schema::user_permissions::dsl::*;
 
         diesel::delete(
-            user_permissions.filter(user_id.eq(item_user_id).and(permission.eq(item_permission)))
+            user_permissions.filter(user_id.eq(item_user_id).and(permission.eq(item_permission))),
         )
-            .execute(db)
+        .execute(db)
     }
 
     pub fn delete_many(
@@ -89,20 +111,14 @@ impl UserPermission {
         diesel::delete(
             user_permissions
                 .filter(user_id.eq(item_user_id))
-                .filter(permission.eq_any(item_permissions))
+                .filter(permission.eq_any(item_permissions)),
         )
-            .execute(db)
+        .execute(db)
     }
 
-    pub fn delete_all(
-        db: &mut Connection,
-        item_user_id: ID,
-    ) -> QueryResult<usize> {
+    pub fn delete_all(db: &mut Connection, item_user_id: ID) -> QueryResult<usize> {
         use crate::auth::schema::user_permissions::dsl::*;
 
-        diesel::delete(
-            user_permissions.filter(user_id.eq(item_user_id)),
-        )
-            .execute(db)
+        diesel::delete(user_permissions.filter(user_id.eq(item_user_id))).execute(db)
     }
 }
diff --git a/create-rust-app/src/auth/permissions/user_role.rs b/create-rust-app/src/auth/permissions/user_role.rs
index a347bf76..49a988ea 100644
--- a/create-rust-app/src/auth/permissions/user_role.rs
+++ b/create-rust-app/src/auth/permissions/user_role.rs
@@ -1,16 +1,18 @@
-use crate::diesel::*;
-use crate::auth::schema::*;
+use diesel::QueryResult;
+use serde::{Deserialize, Serialize};
 
+use crate::auth::schema::*;
+use crate::diesel::*;
 use crate::{
     auth::{user::User, ID, UTC},
     database::Connection,
 };
-use diesel::QueryResult;
-use serde::{Deserialize, Serialize};
 
 #[tsync::tsync]
-#[derive(Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Associations, AsChangeset)]
-#[diesel(table_name=user_roles,belongs_to(User))]
+#[derive(
+    Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Associations, AsChangeset,
+)]
+#[diesel(table_name = user_roles, belongs_to(User))]
 pub struct UserRole {
     /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
     Add columns here in the same order as the schema
@@ -21,7 +23,7 @@ pub struct UserRole {
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, Insertable, AsChangeset)]
-#[diesel(table_name=user_roles)]
+#[diesel(table_name = user_roles)]
 pub struct UserRoleChangeset {
     /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
     Add columns here in the same order as the schema
@@ -41,7 +43,18 @@ impl UserRole {
             .get_result::<UserRole>(db)
     }
 
-    pub fn create_many(db: &mut Connection, items: Vec<UserRoleChangeset>) -> QueryResult<Vec<Self>> {
+    #[cfg(feature = "database_sqlite")]
+    pub fn create_many(db: &mut Connection, items: Vec<UserRoleChangeset>) -> QueryResult<usize> {
+        use crate::auth::schema::user_roles::dsl::*;
+
+        insert_into(user_roles).values(items).execute(db)
+    }
+
+    #[cfg(not(feature = "database_sqlite"))]
+    pub fn create_many(
+        db: &mut Connection,
+        items: Vec<UserRoleChangeset>,
+    ) -> QueryResult<Vec<Self>> {
         use crate::auth::schema::user_roles::dsl::*;
 
         insert_into(user_roles)
@@ -73,7 +86,11 @@ impl UserRole {
             .execute(db)
     }
 
-    pub fn delete_many(db: &mut Connection, item_user_id: ID, item_roles: Vec<String>) -> QueryResult<usize> {
+    pub fn delete_many(
+        db: &mut Connection,
+        item_user_id: ID,
+        item_roles: Vec<String>,
+    ) -> QueryResult<usize> {
         use crate::auth::schema::user_roles::dsl::*;
 
         diesel::delete(user_roles.filter(user_id.eq(item_user_id).and(role.eq_any(item_roles))))
diff --git a/create-rust-app/src/auth/schema.rs b/create-rust-app/src/auth/schema.rs
index e419e110..a818969e 100644
--- a/create-rust-app/src/auth/schema.rs
+++ b/create-rust-app/src/auth/schema.rs
@@ -1,57 +1,9 @@
-table! {
-  role_permissions (role) {
-      role -> Text,
-      permission -> Text,
-      created_at -> Timestamptz,
-  }
-}
-
-table! {
-  user_permissions (user_id, permission) {
-      user_id -> Int4,
-      permission -> Text,
-      created_at -> Timestamptz,
-  }
-}
-
-table! {
-  user_roles (user_id, role) {
-      user_id -> Int4,
-      role -> Text,
-      created_at -> Timestamptz,
-  }
-}
-
-table! {
-  user_sessions (id) {
-      id -> Int4,
-      user_id -> Int4,
-      refresh_token -> Text,
-      device -> Nullable<Text>,
-      created_at -> Timestamptz,
-      updated_at -> Timestamptz,
-  }
-}
-
-table! {
-  users (id) {
-      id -> Int4,
-      email -> Text,
-      hash_password -> Text,
-      activated -> Bool,
-      created_at -> Timestamptz,
-      updated_at -> Timestamptz,
-  }
-}
-
-joinable!(user_permissions -> users (user_id));
-joinable!(user_roles -> users (user_id));
-joinable!(user_sessions -> users (user_id));
-
-allow_tables_to_appear_in_same_query!(
-    role_permissions,
-    user_permissions,
-    user_roles,
-    user_sessions,
-    users,
-);
+#[cfg(feature = "database_sqlite")]
+mod sqlite;
+#[cfg(feature = "database_sqlite")]
+pub use sqlite::*;
+
+#[cfg(feature = "database_postgres")]
+mod postgres;
+#[cfg(feature = "database_postgres")]
+pub use postgres::*;
diff --git a/create-rust-app/src/auth/schema/postgres.rs b/create-rust-app/src/auth/schema/postgres.rs
new file mode 100644
index 00000000..e419e110
--- /dev/null
+++ b/create-rust-app/src/auth/schema/postgres.rs
@@ -0,0 +1,57 @@
+table! {
+  role_permissions (role) {
+      role -> Text,
+      permission -> Text,
+      created_at -> Timestamptz,
+  }
+}
+
+table! {
+  user_permissions (user_id, permission) {
+      user_id -> Int4,
+      permission -> Text,
+      created_at -> Timestamptz,
+  }
+}
+
+table! {
+  user_roles (user_id, role) {
+      user_id -> Int4,
+      role -> Text,
+      created_at -> Timestamptz,
+  }
+}
+
+table! {
+  user_sessions (id) {
+      id -> Int4,
+      user_id -> Int4,
+      refresh_token -> Text,
+      device -> Nullable<Text>,
+      created_at -> Timestamptz,
+      updated_at -> Timestamptz,
+  }
+}
+
+table! {
+  users (id) {
+      id -> Int4,
+      email -> Text,
+      hash_password -> Text,
+      activated -> Bool,
+      created_at -> Timestamptz,
+      updated_at -> Timestamptz,
+  }
+}
+
+joinable!(user_permissions -> users (user_id));
+joinable!(user_roles -> users (user_id));
+joinable!(user_sessions -> users (user_id));
+
+allow_tables_to_appear_in_same_query!(
+    role_permissions,
+    user_permissions,
+    user_roles,
+    user_sessions,
+    users,
+);
diff --git a/create-rust-app/src/auth/schema/sqlite.rs b/create-rust-app/src/auth/schema/sqlite.rs
new file mode 100644
index 00000000..b9c0eacd
--- /dev/null
+++ b/create-rust-app/src/auth/schema/sqlite.rs
@@ -0,0 +1,55 @@
+table! {
+  role_permissions (role, permission) {
+      role -> Text,
+      permission -> Text,
+      created_at -> Timestamp,
+  }
+}
+
+table! {
+  user_permissions (user_id, permission) {
+      user_id -> Integer,
+      permission -> Text,
+      created_at -> Timestamp,
+  }
+}
+
+table! {
+  user_roles (user_id, role) {
+      user_id -> Integer,
+      role -> Text,
+      created_at -> Timestamp,
+  }
+}
+
+table! {
+  user_sessions (id) {
+      id -> Integer,
+      user_id -> Integer,
+      refresh_token -> Text,
+      device -> Nullable<Text>,
+      created_at -> Timestamp,
+  }
+}
+
+table! {
+  users (id) {
+      id -> Integer,
+      email -> Text,
+      hash_password -> Text,
+      activated -> Bool,
+      created_at -> Timestamp,
+  }
+}
+
+joinable!(user_permissions -> users (user_id));
+joinable!(user_roles -> users (user_id));
+joinable!(user_sessions -> users (user_id));
+
+allow_tables_to_appear_in_same_query!(
+    role_permissions,
+    user_permissions,
+    user_roles,
+    user_sessions,
+    users,
+);
diff --git a/create-rust-app/src/auth/user.rs b/create-rust-app/src/auth/user.rs
index 1e6fa3f3..ade3f468 100644
--- a/create-rust-app/src/auth/user.rs
+++ b/create-rust-app/src/auth/user.rs
@@ -1,5 +1,5 @@
-use crate::diesel::*;
 use super::schema::*;
+use crate::diesel::*;
 
 use super::{PaginationParams, ID, UTC};
 use crate::database::Connection;
@@ -8,14 +8,7 @@ use serde::{Deserialize, Serialize};
 
 #[tsync::tsync]
 #[derive(
-    Debug,
-    Serialize,
-    Deserialize,
-    Clone,
-    Queryable,
-    Insertable,
-    Identifiable,
-    AsChangeset,
+    Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Identifiable, AsChangeset,
 )]
 #[diesel(table_name=users)]
 pub struct User {
@@ -29,6 +22,7 @@ pub struct User {
     pub activated: bool,
 
     pub created_at: UTC,
+    #[cfg(not(feature = "database_sqlite"))]
     pub updated_at: UTC,
 }
 
diff --git a/create-rust-app/src/auth/user_session.rs b/create-rust-app/src/auth/user_session.rs
index b500cfe7..850736a9 100644
--- a/create-rust-app/src/auth/user_session.rs
+++ b/create-rust-app/src/auth/user_session.rs
@@ -1,5 +1,5 @@
-use crate::diesel::*;
 use super::schema::*;
+use crate::diesel::*;
 
 use super::user::User;
 use super::{PaginationParams, ID, UTC};
@@ -31,6 +31,7 @@ pub struct UserSession {
     pub device: Option<String>,
 
     pub created_at: UTC,
+    #[cfg(not(feature = "database_sqlite"))]
     pub updated_at: UTC,
 }
 
@@ -65,7 +66,10 @@ impl UserSession {
             .first::<UserSession>(db)
     }
 
-    pub fn find_by_refresh_token(db: &mut Connection, item_refresh_token: &str) -> QueryResult<Self> {
+    pub fn find_by_refresh_token(
+        db: &mut Connection,
+        item_refresh_token: &str,
+    ) -> QueryResult<Self> {
         use super::schema::user_sessions::dsl::*;
 
         user_sessions
@@ -100,7 +104,11 @@ impl UserSession {
             .get_result(db)
     }
 
-    pub fn update(db: &mut Connection, item_id: ID, item: &UserSessionChangeset) -> QueryResult<Self> {
+    pub fn update(
+        db: &mut Connection,
+        item_id: ID,
+        item: &UserSessionChangeset,
+    ) -> QueryResult<Self> {
         use super::schema::user_sessions::dsl::*;
 
         diesel::update(user_sessions.filter(id.eq(item_id)))
diff --git a/create-rust-app/src/database.rs b/create-rust-app/src/database.rs
index 698d843a..59bebefa 100644
--- a/create-rust-app/src/database.rs
+++ b/create-rust-app/src/database.rs
@@ -1,10 +1,13 @@
-use diesel::{
-    r2d2::{self, ConnectionManager, PooledConnection},
-    PgConnection,
-};
+use diesel::r2d2::{self, ConnectionManager, PooledConnection};
 
-pub type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;
-pub type Connection = PooledConnection<ConnectionManager<PgConnection>>;
+#[cfg(feature = "database_postgres")]
+type DbCon = diesel::PgConnection;
+
+#[cfg(feature = "database_sqlite")]
+type DbCon = diesel::SqliteConnection;
+
+pub type Pool = r2d2::Pool<ConnectionManager<DbCon>>;
+pub type Connection = PooledConnection<ConnectionManager<DbCon>>;
 
 #[derive(Clone)]
 pub struct Database {
@@ -17,7 +20,7 @@ impl Database {
             std::env::var("DATABASE_URL").expect("DATABASE_URL environment variable expected.");
         let database_pool = Pool::builder()
             .connection_timeout(std::time::Duration::from_secs(5))
-            .build(ConnectionManager::<PgConnection>::new(database_url))
+            .build(ConnectionManager::<DbCon>::new(database_url))
             .unwrap();
 
         Database {
diff --git a/create-rust-app/src/dev/controller.rs b/create-rust-app/src/dev/controller.rs
index 187bdb01..f6577b3b 100644
--- a/create-rust-app/src/dev/controller.rs
+++ b/create-rust-app/src/dev/controller.rs
@@ -1,8 +1,8 @@
-use diesel::{sql_query, sql_types::Text, query_dsl::RunQueryDsl};
-use diesel_migrations::{FileBasedMigrations, MigrationHarness};
-use serde::{Deserialize, Serialize};
 use crate::auth::{Auth, Role};
 use crate::Database;
+use diesel::{query_dsl::RunQueryDsl, sql_query, sql_types::Text};
+use diesel_migrations::{FileBasedMigrations, MigrationHarness};
+use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Deserialize, QueryableByName)]
 pub struct MyQueryResult {
@@ -58,7 +58,7 @@ pub fn is_connected(db: &Database) -> bool {
 /// checks if a migration is needed
 pub fn needs_migration(db: &Database) -> bool {
     let mut db = db.pool.clone().get().unwrap();
-    
+
     let source = FileBasedMigrations::find_migrations_directory().unwrap();
     MigrationHarness::has_pending_migration(&mut db, source).unwrap()
 }
@@ -69,7 +69,8 @@ pub fn migrate_db(db: &Database) -> bool {
     let mut db = db.pool.clone().get().unwrap();
 
     let source = FileBasedMigrations::find_migrations_directory().unwrap();
-    let has_pending_migrations = MigrationHarness::has_pending_migration(&mut db, source.clone()).unwrap();
+    let has_pending_migrations =
+        MigrationHarness::has_pending_migration(&mut db, source.clone()).unwrap();
 
     if !has_pending_migrations {
         return true;
@@ -88,4 +89,4 @@ pub fn migrate_db(db: &Database) -> bool {
 /// /health
 pub fn health() -> () {
     ()
-}
\ No newline at end of file
+}
diff --git a/create-rust-app/src/dev/endpoints/mod.rs b/create-rust-app/src/dev/endpoints/mod.rs
index a785eb9b..0c53b9eb 100644
--- a/create-rust-app/src/dev/endpoints/mod.rs
+++ b/create-rust-app/src/dev/endpoints/mod.rs
@@ -7,4 +7,3 @@ pub use service_poem::api;
 mod service_actixweb;
 #[cfg(feature = "backend_actix-web")]
 pub use service_actixweb::endpoints;
-
diff --git a/create-rust-app/src/dev/endpoints/service_actixweb.rs b/create-rust-app/src/dev/endpoints/service_actixweb.rs
index 89999bdd..b6fd4c21 100644
--- a/create-rust-app/src/dev/endpoints/service_actixweb.rs
+++ b/create-rust-app/src/dev/endpoints/service_actixweb.rs
@@ -1,12 +1,21 @@
+use crate::{
+    auth::Auth,
+    dev::controller,
+    dev::controller::{HealthCheckResponse, MyQueryResult, MySqlQuery},
+    Database,
+};
+use actix_web::{
+    get, post,
+    web::{Data, Json},
+    HttpResponse, Scope,
+};
 use std::ops::Deref;
-use actix_web::{get, HttpResponse, post, Scope, web::{Data, Json}};
-use crate::{auth::Auth, Database, dev::controller, dev::controller::{HealthCheckResponse, MyQueryResult, MySqlQuery}};
 
 #[post("/db/query")]
 async fn query_db(db: Data<Database>, body: Json<MySqlQuery>) -> HttpResponse {
     match controller::query_db(&db, body.deref()) {
         Ok(result) => HttpResponse::Ok().body(result),
-        Err(t) => HttpResponse::InternalServerError().finish()
+        Err(t) => HttpResponse::InternalServerError().finish(),
     }
 }
 
diff --git a/create-rust-app/src/dev/endpoints/service_poem.rs b/create-rust-app/src/dev/endpoints/service_poem.rs
index ec19014a..4e0a7b24 100644
--- a/create-rust-app/src/dev/endpoints/service_poem.rs
+++ b/create-rust-app/src/dev/endpoints/service_poem.rs
@@ -1,16 +1,25 @@
 use argonautica::config::Version::_0x10;
-use poem::{get, handler, http::StatusCode, post, web::{Json, Data}, Error, IntoResponse, Result, Route};
+use poem::{
+    get, handler,
+    http::StatusCode,
+    post,
+    web::{Data, Json},
+    Error, IntoResponse, Result, Route,
+};
 
-use diesel::{sql_types::Text, sql_query, QueryableByName, RunQueryDsl};
+use diesel::{sql_query, sql_types::Text, QueryableByName, RunQueryDsl};
 use serde::{Deserialize, Serialize};
 
-use crate::dev::{controller, controller::{HealthCheckResponse, MySqlQuery, MyQueryResult}};
+use crate::dev::{
+    controller,
+    controller::{HealthCheckResponse, MyQueryResult, MySqlQuery},
+};
 
+use crate::auth::Role;
 use crate::{
     auth::{Auth, Permission},
     Database,
 };
-use crate::auth::Role;
 
 #[handler]
 async fn health() -> Result<impl IntoResponse> {
@@ -18,8 +27,8 @@ async fn health() -> Result<impl IntoResponse> {
     Ok(Json(HealthCheckResponse {
         message: "healthy".to_string(),
     })
-        .with_status(StatusCode::OK)
-        .into_response())
+    .with_status(StatusCode::OK)
+    .into_response())
 }
 
 #[handler]
@@ -42,7 +51,7 @@ async fn needs_migration(db: Data<&Database>) -> Result<impl IntoResponse> {
 async fn query(db: Data<&Database>, body: Json<MySqlQuery>) -> Result<impl IntoResponse> {
     match controller::query_db(db.0, &body) {
         Ok(result) => Ok(result),
-        Err(_) => Err(Error::from_status(StatusCode::INTERNAL_SERVER_ERROR))
+        Err(_) => Err(Error::from_status(StatusCode::INTERNAL_SERVER_ERROR)),
     }
 }
 
diff --git a/create-rust-app/src/lib.rs b/create-rust-app/src/lib.rs
index f36eb8c3..9d3c8e17 100644
--- a/create-rust-app/src/lib.rs
+++ b/create-rust-app/src/lib.rs
@@ -1,5 +1,7 @@
 #[cfg(all(feature = "backend_actix-web", feature = "backend_poem"))]
-compile_error!("feature \"backend_actix-web\" and feature \"backend_poem\" cannot be enabled at the same time");
+compile_error!(
+    "feature \"backend_actix-web\" and feature \"backend_poem\" cannot be enabled at the same time"
+);
 
 // #[cfg(not(any(feature = "backend_poem", feature = "backend_actix-web")))]
 // compile_error!("Please enable one of the backend features (options: 'backend_actix-web', 'backend-poem')");
@@ -7,7 +9,8 @@ compile_error!("feature \"backend_actix-web\" and feature \"backend_poem\" canno
 mod util;
 pub use util::*;
 
-#[macro_use] extern crate diesel;
+#[macro_use]
+extern crate diesel;
 
 #[cfg(feature = "plugin_auth")]
 pub mod auth;
@@ -16,7 +19,7 @@ pub mod auth;
 pub mod dev;
 
 mod database;
-pub use database::{Database, Pool, Connection};
+pub use database::{Connection, Database, Pool};
 
 #[cfg(feature = "backend_poem")]
 mod logger;
@@ -26,7 +29,7 @@ pub use logger::Logger as PoemLogger;
 #[cfg(feature = "plugin_storage")]
 mod storage;
 #[cfg(feature = "plugin_storage")]
-pub use storage::{Storage, Attachment, AttachmentData, AttachmentBlob};
+pub use storage::{Attachment, AttachmentBlob, AttachmentData, Storage};
 
 mod mailer;
 pub use mailer::Mailer;
@@ -39,8 +42,8 @@ pub use mailer::Mailer;
 pub struct AppData {
     pub mailer: Mailer,
     pub database: Database,
-    #[cfg(feature= "plugin_storage")]
-    pub storage: storage::Storage
+    #[cfg(feature = "plugin_storage")]
+    pub storage: storage::Storage,
 }
 
 pub fn setup() -> AppData {
@@ -56,7 +59,7 @@ pub fn setup() -> AppData {
         // diesel_migrations::embed_migrations!();
     }
 
-    #[cfg(feature="plugin_auth")]
+    #[cfg(feature = "plugin_auth")]
     if std::env::var("SECRET_KEY").is_err() {
         panic!("No SECRET_KEY environment variable set!");
     }
@@ -70,8 +73,8 @@ pub fn setup() -> AppData {
     AppData {
         mailer: Mailer::new(),
         database: Database::new(),
-        #[cfg(feature= "plugin_storage")]
-        storage: storage::Storage::new()
+        #[cfg(feature = "plugin_storage")]
+        storage: storage::Storage::new(),
     }
 }
 
diff --git a/create-rust-app/src/mailer.rs b/create-rust-app/src/mailer.rs
index fe07c746..733a94f3 100644
--- a/create-rust-app/src/mailer.rs
+++ b/create-rust-app/src/mailer.rs
@@ -36,9 +36,7 @@ impl Mailer {
 
     pub fn check_environment_variables() {
         if std::env::var("SMTP_FROM_ADDRESS").is_err() {
-            println!(
-                "Note: Mailing disabled; 'SMTP_FROM_ADDRESS' not set."
-            );
+            println!("Note: Mailing disabled; 'SMTP_FROM_ADDRESS' not set.");
         }
 
         if std::env::var("SMTP_SERVER").is_err() {
@@ -53,10 +51,12 @@ impl Mailer {
             println!("Note: Mailing disabled; 'SMTP_PASSWORD' not set.");
         }
 
-        if std::env::var("SEND_MAIL").is_err() || !std::env::var("SEND_MAIL").unwrap().eq_ignore_ascii_case("true") {
-            println!(
-                "Note: Mailing disabled; 'SEND_MAIL' not 'true'."
-            );
+        if std::env::var("SEND_MAIL").is_err()
+            || !std::env::var("SEND_MAIL")
+                .unwrap()
+                .eq_ignore_ascii_case("true")
+        {
+            println!("Note: Mailing disabled; 'SEND_MAIL' not 'true'.");
         }
     }
 
diff --git a/create-rust-app/src/storage/attachment.rs b/create-rust-app/src/storage/attachment.rs
index a0c55db9..3c3612e2 100644
--- a/create-rust-app/src/storage/attachment.rs
+++ b/create-rust-app/src/storage/attachment.rs
@@ -1,19 +1,21 @@
-use std::sync::Arc;
-use diesel::QueryResult;
 use diesel::result::{DatabaseErrorKind, Error};
+use diesel::QueryResult;
 use md5;
 use mime_guess;
 use serde::{Deserialize, Serialize};
+use std::sync::Arc;
 use uuid::Uuid;
 
-use crate::{Connection, Pool};
 use crate::diesel::*;
-use crate::storage::{AttachmentBlob, ID, schema, UTC};
 use crate::storage::attachment_blob::AttachmentBlobChangeset;
+use crate::storage::{schema, AttachmentBlob, ID, UTC};
+use crate::{Connection, Pool};
 
 use super::{schema::*, Storage};
 
-#[derive(Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Identifiable, AsChangeset)]
+#[derive(
+    Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Identifiable, AsChangeset,
+)]
 #[diesel(table_name=attachments)]
 pub struct Attachment {
     pub id: ID,
@@ -37,20 +39,35 @@ pub struct AttachmentChangeset {
 
 pub struct AttachmentData {
     pub data: Vec<u8>,
-    pub file_name: Option<String>
+    pub file_name: Option<String>,
 }
 
 impl Attachment {
     /// in actix_web we don't need to support send+sync handlers, so we can use the &mut Connection directly.
     #[cfg(feature = "backend_actix-web")]
-    pub async fn attach(db: &mut Connection, storage: &Storage, name: String, record_type: String, record_id: ID, data: AttachmentData, allow_multiple: bool, overwrite_existing: bool) -> Result<String, String> {
+    pub async fn attach(
+        db: &mut Connection,
+        storage: &Storage,
+        name: String,
+        record_type: String,
+        record_id: ID,
+        data: AttachmentData,
+        allow_multiple: bool,
+        overwrite_existing: bool,
+    ) -> Result<String, String> {
         let checksum = format!("{:x}", md5::compute(&data.data));
         let file_name = data.file_name.clone();
-        let content_type = if file_name.is_some() { mime_guess::from_path(file_name.unwrap()).first_raw() } else { None }.map(|t| t.to_string());
+        let content_type = if file_name.is_some() {
+            mime_guess::from_path(file_name.unwrap()).first_raw()
+        } else {
+            None
+        }
+        .map(|t| t.to_string());
         let key = Uuid::new_v4().to_string();
 
         if !allow_multiple {
-            let existing = Attachment::find_for_record(db, name.clone(), record_type.clone(), record_id);
+            let existing =
+                Attachment::find_for_record(db, name.clone(), record_type.clone(), record_id);
 
             if existing.is_ok() {
                 // one already exists, we need to delete it
@@ -60,34 +77,45 @@ impl Attachment {
                     })?;
                 } else {
                     // throw the error
-                    return Err(format!("Only 1 attachment is allowed for '{name}' type attachments on '{record_type}'", name=name.clone(), record_type=record_type.clone()))
+                    return Err(format!("Only 1 attachment is allowed for '{name}' type attachments on '{record_type}'", name=name.clone(), record_type=record_type.clone()));
                 }
             }
         }
 
         let attached = diesel::connection::Connection::transaction::<Self, Error, _>(db, |db| {
-            let blob = AttachmentBlob::create(db, &AttachmentBlobChangeset {
-                byte_size: data.data.len() as i64,
-                service_name: "s3".to_string(),
-                key: key.clone(),
-                checksum: checksum.clone(),
-                content_type: content_type.clone(),
-                file_name: data.file_name.clone()
-            })?;
-
-            let attached = Attachment::create(db, &AttachmentChangeset {
-                blob_id: blob.id,
-                record_id,
-                record_type,
-                name,
-            })?;
+            let blob = AttachmentBlob::create(
+                db,
+                &AttachmentBlobChangeset {
+                    byte_size: data.data.len() as i64,
+                    service_name: "s3".to_string(),
+                    key: key.clone(),
+                    checksum: checksum.clone(),
+                    content_type: content_type.clone(),
+                    file_name: data.file_name.clone().unwrap_or(String::new()),
+                },
+            )?;
+
+            let attached = Attachment::create(
+                db,
+                &AttachmentChangeset {
+                    blob_id: blob.id,
+                    record_id,
+                    record_type,
+                    name,
+                },
+            )?;
 
             Ok(attached)
-        }).map_err(|err| {
-            err.to_string()
-        })?;
-
-        let upload_result = storage.upload(key.clone(), data.data, content_type.clone().unwrap_or("".to_string()), checksum.clone())
+        })
+        .map_err(|err| err.to_string())?;
+
+        let upload_result = storage
+            .upload(
+                key.clone(),
+                data.data,
+                content_type.clone().unwrap_or("".to_string()),
+                checksum.clone(),
+            )
             .await
             .map(|_| key);
 
@@ -104,16 +132,31 @@ impl Attachment {
 
     /// in poem, we need to pass in the pool itself because the Connection is not Send+Sync which poem handlers require
     #[cfg(feature = "backend_poem")]
-    pub async fn attach(pool: Arc<Pool>, storage: &Storage, name: String, record_type: String, record_id: ID, data: AttachmentData, allow_multiple: bool, overwrite_existing: bool) -> Result<String, String> {
+    pub async fn attach(
+        pool: Arc<Pool>,
+        storage: &Storage,
+        name: String,
+        record_type: String,
+        record_id: ID,
+        data: AttachmentData,
+        allow_multiple: bool,
+        overwrite_existing: bool,
+    ) -> Result<String, String> {
         let mut db = pool.clone().get().unwrap();
 
         let checksum = format!("{:x}", md5::compute(&data.data));
         let file_name = data.file_name.clone();
-        let content_type = if file_name.is_some() { mime_guess::from_path(file_name.unwrap()).first_raw() } else { None }.map(|t| t.to_string());
+        let content_type = if file_name.is_some() {
+            mime_guess::from_path(file_name.unwrap()).first_raw()
+        } else {
+            None
+        }
+        .map(|t| t.to_string());
         let key = Uuid::new_v4().to_string();
 
         if !allow_multiple {
-            let existing = Attachment::find_for_record(&mut db, name.clone(), record_type.clone(), record_id);
+            let existing =
+                Attachment::find_for_record(&mut db, name.clone(), record_type.clone(), record_id);
 
             if existing.is_ok() {
                 // one already exists, we need to delete it
@@ -123,34 +166,46 @@ impl Attachment {
                     })?;
                 } else {
                     // throw the error
-                    return Err(format!("Only 1 attachment is allowed for '{name}' type attachments on '{record_type}'", name=name.clone(), record_type=record_type.clone()))
+                    return Err(format!("Only 1 attachment is allowed for '{name}' type attachments on '{record_type}'", name=name.clone(), record_type=record_type.clone()));
                 }
             }
         }
 
-        let attached = diesel::connection::Connection::transaction::<Self, Error, _>(&mut db, |db| {
-            let blob = AttachmentBlob::create(db, &AttachmentBlobChangeset {
-                byte_size: data.data.len() as i64,
-                service_name: "s3".to_string(),
-                key: key.clone(),
-                checksum: checksum.clone(),
-                content_type: content_type.clone(),
-                file_name: data.file_name.clone()
-            })?;
-
-            let attached = Attachment::create(db, &AttachmentChangeset {
-                blob_id: blob.id,
-                record_id,
-                record_type,
-                name,
-            })?;
-
-            Ok(attached)
-        }).map_err(|err| {
-            err.to_string()
-        })?;
-
-        let upload_result = storage.upload(key.clone(), data.data, content_type.clone().unwrap_or("".to_string()), checksum.clone())
+        let attached =
+            diesel::connection::Connection::transaction::<Self, Error, _>(&mut db, |db| {
+                let blob = AttachmentBlob::create(
+                    db,
+                    &AttachmentBlobChangeset {
+                        byte_size: data.data.len() as i64,
+                        service_name: "s3".to_string(),
+                        key: key.clone(),
+                        checksum: checksum.clone(),
+                        content_type: content_type.clone(),
+                        file_name: data.file_name.clone().unwrap_or(String::new()),
+                    },
+                )?;
+
+                let attached = Attachment::create(
+                    db,
+                    &AttachmentChangeset {
+                        blob_id: blob.id,
+                        record_id,
+                        record_type,
+                        name,
+                    },
+                )?;
+
+                Ok(attached)
+            })
+            .map_err(|err| err.to_string())?;
+
+        let upload_result = storage
+            .upload(
+                key.clone(),
+                data.data,
+                content_type.clone().unwrap_or("".to_string()),
+                checksum.clone(),
+            )
             .await
             .map(|_| key);
 
@@ -168,11 +223,12 @@ impl Attachment {
     /// in actix_web we don't need to support send+sync handlers, so we can use the &mut Connection directly.
     #[cfg(feature = "backend_actix-web")]
     pub async fn detach(db: &mut Connection, storage: &Storage, item_id: ID) -> Result<(), String> {
-        let attached = Attachment::find_by_id(db, item_id).map_err(|_| "Could not load attachment")?;
-        let blob = AttachmentBlob::find_by_id(db, attached.blob_id).map_err(|_| "Could not load attachment blob")?;
+        let attached =
+            Attachment::find_by_id(db, item_id).map_err(|_| "Could not load attachment")?;
+        let blob = AttachmentBlob::find_by_id(db, attached.blob_id)
+            .map_err(|_| "Could not load attachment blob")?;
 
-        let delete_result = storage.delete(blob.key.clone())
-            .await;
+        let delete_result = storage.delete(blob.key.clone()).await;
 
         if delete_result.is_err() {
             // we continue even if there's an error deleting the actual object
@@ -187,9 +243,8 @@ impl Attachment {
             AttachmentBlob::delete(db, blob.id)?;
 
             Ok(())
-        }).map_err(|err| {
-            err.to_string()
-        })?;
+        })
+        .map_err(|err| err.to_string())?;
 
         Ok(())
     }
@@ -199,11 +254,12 @@ impl Attachment {
     pub async fn detach(pool: Arc<Pool>, storage: &Storage, item_id: ID) -> Result<(), String> {
         let mut db = pool.get().unwrap();
 
-        let attached = Attachment::find_by_id(&mut db, item_id).map_err(|_| "Could not load attachment")?;
-        let blob = AttachmentBlob::find_by_id(&mut db, attached.blob_id).map_err(|_| "Could not load attachment blob")?;
+        let attached =
+            Attachment::find_by_id(&mut db, item_id).map_err(|_| "Could not load attachment")?;
+        let blob = AttachmentBlob::find_by_id(&mut db, attached.blob_id)
+            .map_err(|_| "Could not load attachment blob")?;
 
-        let delete_result = storage.delete(blob.key.clone())
-            .await;
+        let delete_result = storage.delete(blob.key.clone()).await;
 
         if delete_result.is_err() {
             // we continue even if there's an error deleting the actual object
@@ -218,19 +274,35 @@ impl Attachment {
             AttachmentBlob::delete(db, blob.id)?;
 
             Ok(())
-        }).map_err(|err| {
-            err.to_string()
-        })?;
+        })
+        .map_err(|err| err.to_string())?;
 
         Ok(())
     }
 
-    pub async fn detach_all(db: &mut Connection, storage: &Storage, name: String, record_type: String, record_id: ID) -> Result<(), String> {
-        let attached = Attachment::find_all_for_record(db, name, record_type, record_id).map_err(|_| "Could not load attachments")?;
-        let attached_ids = attached.iter().map(|attached| attached.id).collect::<Vec<_>>();
-        let blob_ids = attached.iter().map(|attached| attached.blob_id).collect::<Vec<_>>();
-        let blobs = AttachmentBlob::find_all_by_id(db, blob_ids.clone()).map_err(|_| "Could not load attachment blobs")?;
-        let keys = blobs.iter().map(|blob| blob.key.to_string()).collect::<Vec<_>>();
+    pub async fn detach_all(
+        db: &mut Connection,
+        storage: &Storage,
+        name: String,
+        record_type: String,
+        record_id: ID,
+    ) -> Result<(), String> {
+        let attached = Attachment::find_all_for_record(db, name, record_type, record_id)
+            .map_err(|_| "Could not load attachments")?;
+        let attached_ids = attached
+            .iter()
+            .map(|attached| attached.id)
+            .collect::<Vec<_>>();
+        let blob_ids = attached
+            .iter()
+            .map(|attached| attached.blob_id)
+            .collect::<Vec<_>>();
+        let blobs = AttachmentBlob::find_all_by_id(db, blob_ids.clone())
+            .map_err(|_| "Could not load attachment blobs")?;
+        let keys = blobs
+            .iter()
+            .map(|blob| blob.key.to_string())
+            .collect::<Vec<_>>();
 
         let delete_result = storage.delete_many(keys).await;
 
@@ -247,9 +319,8 @@ impl Attachment {
             AttachmentBlob::delete_all(db, blob_ids)?;
 
             Ok(())
-        }).map_err(|err| {
-            err.to_string()
-        })?;
+        })
+        .map_err(|err| err.to_string())?;
 
         Ok(())
     }
@@ -268,7 +339,12 @@ impl Attachment {
             .first(db)
     }
 
-    pub fn find_for_record(db: &mut Connection, item_name: String, item_record_type: String, item_record_id: ID) -> QueryResult<Self> {
+    pub fn find_for_record(
+        db: &mut Connection,
+        item_name: String,
+        item_record_type: String,
+        item_record_id: ID,
+    ) -> QueryResult<Self> {
         schema::attachments::table
             .filter(schema::attachments::name.eq(item_name))
             .filter(schema::attachments::record_type.eq(item_record_type))
@@ -276,7 +352,12 @@ impl Attachment {
             .first::<Self>(db)
     }
 
-    pub fn find_all_for_record(db: &mut Connection, item_name: String, item_record_type: String, item_record_id: ID) -> QueryResult<Vec<Self>> {
+    pub fn find_all_for_record(
+        db: &mut Connection,
+        item_name: String,
+        item_record_type: String,
+        item_record_id: ID,
+    ) -> QueryResult<Vec<Self>> {
         schema::attachments::table
             .filter(schema::attachments::name.eq(item_name))
             .filter(schema::attachments::record_type.eq(item_record_type))
@@ -284,7 +365,12 @@ impl Attachment {
             .get_results::<Self>(db)
     }
 
-    pub fn find_all_for_records(db: &mut Connection, item_name: String, item_record_type: String, item_record_ids: Vec<ID>) -> QueryResult<Vec<Self>> {
+    pub fn find_all_for_records(
+        db: &mut Connection,
+        item_name: String,
+        item_record_type: String,
+        item_record_ids: Vec<ID>,
+    ) -> QueryResult<Vec<Self>> {
         schema::attachments::table
             .filter(schema::attachments::name.eq(item_name))
             .filter(schema::attachments::record_type.eq(item_record_type))
@@ -303,14 +389,12 @@ impl Attachment {
     fn delete(db: &mut Connection, item_id: ID) -> QueryResult<usize> {
         use super::schema::attachments::dsl::*;
 
-        diesel::delete(attachments.filter(id.eq(item_id))).execute(db)
+        diesel::delete(attachments.filter(schema::attachments::id.eq(item_id))).execute(db)
     }
 
     fn delete_all(db: &mut Connection, item_ids: Vec<ID>) -> QueryResult<usize> {
         use super::schema::attachments::dsl::*;
 
-        diesel::delete(attachments.filter(id.eq_any(item_ids))).execute(db)
+        diesel::delete(attachments.filter(schema::attachments::id.eq_any(item_ids))).execute(db)
     }
-
 }
-
diff --git a/create-rust-app/src/storage/attachment_blob.rs b/create-rust-app/src/storage/attachment_blob.rs
index f2b77a37..50cf34dc 100644
--- a/create-rust-app/src/storage/attachment_blob.rs
+++ b/create-rust-app/src/storage/attachment_blob.rs
@@ -1,19 +1,18 @@
-use diesel::QueryResult;
 use serde::{Deserialize, Serialize};
 
 use crate::Connection;
 use crate::diesel::*;
-use crate::storage::{ID, schema, UTC};
+use crate::storage::{ID, schema, schema::*, UTC};
 
-use super::schema::*;
-
-#[derive(Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Identifiable, AsChangeset)]
-#[diesel(table_name=attachment_blobs)]
+#[derive(
+Debug, Serialize, Deserialize, Clone, Queryable, Insertable, Identifiable, AsChangeset,
+)]
+#[diesel(table_name = attachment_blobs)]
 pub struct AttachmentBlob {
     pub id: ID,
 
     pub key: String,
-    pub file_name: Option<String>,
+    pub file_name: String,
     pub content_type: Option<String>,
     pub byte_size: i64,
     pub checksum: String,
@@ -21,15 +20,16 @@ pub struct AttachmentBlob {
 
     pub created_at: UTC,
 }
+
 #[derive(Debug, Serialize, Deserialize, Clone, Insertable, AsChangeset)]
-#[diesel(table_name=attachment_blobs)]
+#[diesel(table_name = attachment_blobs)]
 pub struct AttachmentBlobChangeset {
     pub key: String,
-    pub file_name: Option<String>,
+    pub file_name: String,
     pub content_type: Option<String>,
     pub byte_size: i64,
     pub checksum: String,
-    pub service_name: String
+    pub service_name: String,
 }
 
 impl AttachmentBlob {
@@ -44,13 +44,17 @@ impl AttachmentBlob {
     pub fn find_by_id(db: &mut Connection, item_id: ID) -> QueryResult<Self> {
         use super::schema::attachment_blobs::dsl::*;
 
-        attachment_blobs.filter(id.eq(item_id)).first::<AttachmentBlob>(db)
+        attachment_blobs
+            .filter(schema::attachment_blobs::id.eq(item_id))
+            .first::<AttachmentBlob>(db)
     }
 
     pub fn find_all_by_id(db: &mut Connection, item_ids: Vec<ID>) -> QueryResult<Vec<Self>> {
         use super::schema::attachment_blobs::dsl::*;
 
-        attachment_blobs.filter(id.eq_any(item_ids)).load::<AttachmentBlob>(db)
+        attachment_blobs
+            .filter(schema::attachment_blobs::id.eq_any(item_ids))
+            .load::<AttachmentBlob>(db)
     }
 
     // fn read_all(db: &mut Connection, pagination: &PaginationParams) -> QueryResult<Vec<Self>> {
@@ -72,13 +76,15 @@ impl AttachmentBlob {
     // }
 
     pub fn delete(db: &mut Connection, item_id: ID) -> QueryResult<usize> {
-        let query = schema::attachment_blobs::table.filter(schema::attachment_blobs::id.eq(item_id));
+        let query =
+            schema::attachment_blobs::table.filter(schema::attachment_blobs::id.eq(item_id));
 
         diesel::delete(query).execute(db)
     }
 
     pub fn delete_all(db: &mut Connection, item_ids: Vec<ID>) -> QueryResult<usize> {
-        let query = schema::attachment_blobs::table.filter(schema::attachment_blobs::id.eq_any(item_ids));
+        let query =
+            schema::attachment_blobs::table.filter(schema::attachment_blobs::id.eq_any(item_ids));
 
         diesel::delete(query).execute(db)
     }
diff --git a/create-rust-app/src/storage/mod.rs b/create-rust-app/src/storage/mod.rs
index d589aa64..054191c9 100644
--- a/create-rust-app/src/storage/mod.rs
+++ b/create-rust-app/src/storage/mod.rs
@@ -2,41 +2,44 @@ use std::path::PathBuf;
 use std::str::FromStr;
 use std::time::Duration;
 
-use aws_sdk_s3::{Client, Config, Endpoint};
 use aws_sdk_s3::model::{Delete, ObjectIdentifier};
 use aws_sdk_s3::presigning::config::PresigningConfig;
 use aws_sdk_s3::types::ByteStream;
 use aws_sdk_s3::types::SdkError::*;
-use aws_types::Credentials;
+use aws_sdk_s3::{Client, Config, Endpoint};
 use aws_types::region::Region;
+use aws_types::Credentials;
+use base64;
 use http::{HeaderMap, Uri};
 use tokio::fs::File;
 use tokio::io::AsyncWriteExt;
-use base64;
 
 pub use attachment::{Attachment, AttachmentData};
 pub use attachment_blob::AttachmentBlob;
 
-mod schema;
 mod attachment;
 mod attachment_blob;
+mod schema;
 
 #[tsync::tsync]
 type ID = i32;
 
 #[tsync::tsync]
+#[cfg(not(feature = "database_sqlite"))]
 type UTC = chrono::DateTime<chrono::Utc>;
+#[cfg(feature = "database_sqlite")]
+type UTC = chrono::NaiveDateTime;
 
 #[derive(Clone)]
 pub struct Storage {
     client: Option<Client>,
     bucket: String,
-    host: String
+    host: String,
 }
 
 pub struct UploadURI {
     pub headers: HeaderMap,
-    pub uri: Uri
+    pub uri: Uri,
 }
 
 impl Storage {
@@ -53,13 +56,9 @@ impl Storage {
                 self.error_string("Could not download object", key.clone(), err.to_string())
             })?;
 
-        let data = response
-            .body
-            .collect()
-            .await
-            .map_err(|err| {
-                self.error_string("Could not download object", key.clone(), err.to_string())
-            })?;
+        let data = response.body.collect().await.map_err(|err| {
+            self.error_string("Could not download object", key.clone(), err.to_string())
+        })?;
 
         let mut file = File::create(to_path).await.map_err(|err| {
             self.error_string("Could not download object", key.clone(), err.to_string())
@@ -74,32 +73,55 @@ impl Storage {
 
     /// if `expires_in` is `None`, then we assume the bucket is publicly accessible and return the
     /// public URL. For this to work, you have to make sure the bucket's policy allows public access.
-    pub async fn download_uri(&self, key: String, expires_in: Option<Duration>) -> Result<String, String> {
+    pub async fn download_uri(
+        &self,
+        key: String,
+        expires_in: Option<Duration>,
+    ) -> Result<String, String> {
         if expires_in.is_none() {
             let host = self.host.clone();
-            let host = if host.ends_with("/") { host } else { format!("{host}/") };
+            let host = if host.ends_with("/") {
+                host
+            } else {
+                format!("{host}/")
+            };
             let bucket = &self.bucket;
-            return Ok(format!("{host}{bucket}/{key}"))
+            return Ok(format!("{host}{bucket}/{key}"));
         }
-        let expires_in=  expires_in.unwrap();
+        let expires_in = expires_in.unwrap();
 
         let client = self.client_or_error()?;
 
-        let response = client.get_object()
+        let response = client
+            .get_object()
             .bucket(&self.bucket)
             .key(key.clone())
             .presigned(PresigningConfig::expires_in(expires_in).map_err(|err| {
-                self.error_string("Could not retrieve download URI", key.clone(), err.to_string())
+                self.error_string(
+                    "Could not retrieve download URI",
+                    key.clone(),
+                    err.to_string(),
+                )
             })?)
             .await
             .map_err(|err| {
-                self.error_string("Could not retrieve download URI", key.clone(), err.to_string())
+                self.error_string(
+                    "Could not retrieve download URI",
+                    key.clone(),
+                    err.to_string(),
+                )
             })?;
 
         Ok(response.uri().to_string())
     }
 
-    pub async fn upload(&self, key: String, bytes: Vec<u8>, content_type: String, content_md5: String) -> Result<(), String> {
+    pub async fn upload(
+        &self,
+        key: String,
+        bytes: Vec<u8>,
+        content_type: String,
+        content_md5: String,
+    ) -> Result<(), String> {
         let stream = ByteStream::from(bytes);
 
         let client = self.client_or_error()?;
@@ -129,7 +151,11 @@ impl Storage {
             .bucket(&self.bucket)
             .key(&key)
             .presigned(PresigningConfig::expires_in(expires_in).map_err(|err| {
-                self.error_string("Could not retrieve upload URI", key.clone(), err.to_string())
+                self.error_string(
+                    "Could not retrieve upload URI",
+                    key.clone(),
+                    err.to_string(),
+                )
             })?)
             .await
             .map_err(|err| {
@@ -138,7 +164,7 @@ impl Storage {
 
         let upload_uri = UploadURI {
             uri: response.uri().clone(),
-            headers: response.headers().clone()
+            headers: response.headers().clone(),
         };
 
         Ok(upload_uri)
@@ -163,7 +189,14 @@ impl Storage {
     pub async fn delete_many(&self, keys: Vec<String>) -> Result<(), String> {
         let client = self.client_or_error()?;
 
-        let ids = keys.iter().map(|k| ObjectIdentifier::builder().set_key(Some(k.to_string())).build()).collect::<Vec<ObjectIdentifier>>();
+        let ids = keys
+            .iter()
+            .map(|k| {
+                ObjectIdentifier::builder()
+                    .set_key(Some(k.to_string()))
+                    .build()
+            })
+            .collect::<Vec<ObjectIdentifier>>();
         let delete = Delete::builder().set_objects(Some(ids)).build();
 
         client
@@ -173,7 +206,11 @@ impl Storage {
             .send()
             .await
             .map_err(|err| {
-                self.error_string("Could not delete objects", format!("{:#?}", keys), err.to_string())
+                self.error_string(
+                    "Could not delete objects",
+                    format!("{:#?}", keys),
+                    err.to_string(),
+                )
             })?;
 
         Ok(())
@@ -185,7 +222,10 @@ impl Storage {
     }
 
     fn client_or_error(&self) -> Result<&Client, String> {
-        self.client.as_ref().ok_or("The storage is not available; did you set the right environment variables?".to_string())
+        self.client.as_ref().ok_or(
+            "The storage is not available; did you set the right environment variables?"
+                .to_string(),
+        )
     }
 
     fn check_environment_variables() {
@@ -210,18 +250,31 @@ impl Storage {
         }
     }
 
-    fn init(host: String, region: String, access_key_id: String, secret_access_key: String) -> Result<Option<Client>, String> {
+    fn init(
+        host: String,
+        region: String,
+        access_key_id: String,
+        secret_access_key: String,
+    ) -> Result<Option<Client>, String> {
         Storage::check_environment_variables();
 
         let host = host.clone();
         let region = Region::new(region);
         let s3_config = Config::builder()
             .region(region)
-            .endpoint_resolver(Endpoint::immutable(Uri::from_str(host.as_str()).map_err(|err| {
-                let error = err.to_string();
-                format!("Could not initialize storage (error: '{error}')")
-            })?))
-            .credentials_provider(Credentials::new(access_key_id, secret_access_key, None, None, "UNNAMED_PROVIDER"))
+            .endpoint_resolver(Endpoint::immutable(Uri::from_str(host.as_str()).map_err(
+                |err| {
+                    let error = err.to_string();
+                    format!("Could not initialize storage (error: '{error}')")
+                },
+            )?))
+            .credentials_provider(Credentials::new(
+                access_key_id,
+                secret_access_key,
+                None,
+                None,
+                "UNNAMED_PROVIDER",
+            ))
             .build();
         let client = Client::from_conf(s3_config);
 
@@ -235,12 +288,13 @@ impl Storage {
         let access_key_id = std::env::var("S3_ACCESS_KEY_ID").unwrap_or("".to_string());
         let secret_access_key = std::env::var("S3_SECRET_ACCESS_KEY").unwrap_or("".to_string());
 
-        let client = Storage::init(host.clone(), region, access_key_id, secret_access_key).unwrap_or(None);
+        let client =
+            Storage::init(host.clone(), region, access_key_id, secret_access_key).unwrap_or(None);
 
         Storage {
             client,
             bucket,
-            host
+            host,
         }
     }
-}
\ No newline at end of file
+}
diff --git a/create-rust-app/src/storage/schema.rs b/create-rust-app/src/storage/schema.rs
index 53efcd01..a818969e 100644
--- a/create-rust-app/src/storage/schema.rs
+++ b/create-rust-app/src/storage/schema.rs
@@ -1,30 +1,9 @@
-table! {
-    attachment_blobs (id) {
-        id -> Int4,
-        key -> Text,
-        file_name -> Nullable<Text>,
-        content_type -> Nullable<Text>,
-        byte_size -> Int8,
-        checksum -> Text,
-        service_name -> Text,
-        created_at -> Timestamptz,
-    }
-}
+#[cfg(feature = "database_sqlite")]
+mod sqlite;
+#[cfg(feature = "database_sqlite")]
+pub use sqlite::*;
 
-table! {
-    attachments (id) {
-        id -> Int4,
-        name -> Text,
-        record_type -> Text,
-        record_id -> Int4,
-        blob_id -> Int4,
-        created_at -> Timestamptz,
-    }
-}
-
-joinable!(attachments -> attachment_blobs (blob_id));
-
-allow_tables_to_appear_in_same_query!(
-    attachment_blobs,
-    attachments,
-);
+#[cfg(feature = "database_postgres")]
+mod postgres;
+#[cfg(feature = "database_postgres")]
+pub use postgres::*;
diff --git a/create-rust-app/src/storage/schema/postgres.rs b/create-rust-app/src/storage/schema/postgres.rs
new file mode 100644
index 00000000..f061b7c2
--- /dev/null
+++ b/create-rust-app/src/storage/schema/postgres.rs
@@ -0,0 +1,27 @@
+table! {
+    attachment_blobs (id) {
+        id -> Int4,
+        key -> Text,
+        file_name -> Text,
+        content_type -> Nullable<Text>,
+        byte_size -> Int8,
+        checksum -> Text,
+        service_name -> Text,
+        created_at -> Timestamptz,
+    }
+}
+
+table! {
+    attachments (id) {
+        id -> Int4,
+        name -> Text,
+        record_type -> Text,
+        record_id -> Int4,
+        blob_id -> Int4,
+        created_at -> Timestamptz,
+    }
+}
+
+joinable!(attachments -> attachment_blobs (blob_id));
+
+allow_tables_to_appear_in_same_query!(attachment_blobs, attachments,);
diff --git a/create-rust-app/src/storage/schema/sqlite.rs b/create-rust-app/src/storage/schema/sqlite.rs
new file mode 100644
index 00000000..8f4c439a
--- /dev/null
+++ b/create-rust-app/src/storage/schema/sqlite.rs
@@ -0,0 +1,27 @@
+table! {
+  attachment_blobs (id) {
+      id -> Integer,
+      key -> Text,
+      file_name -> Text,
+      content_type -> Nullable<Text>,
+      byte_size -> BigInt,
+      checksum -> Text,
+      service_name -> Text,
+      created_at -> Timestamp,
+  }
+}
+
+table! {
+  attachments (id) {
+      id -> Integer,
+      name -> Text,
+      record_type -> Text,
+      record_id -> Integer,
+      blob_id -> Integer,
+      created_at -> Timestamp,
+  }
+}
+
+joinable!(attachments -> attachment_blobs (blob_id));
+
+allow_tables_to_appear_in_same_query!(attachment_blobs, attachments,);
diff --git a/create-rust-app/src/util/actix_web_utils.rs b/create-rust-app/src/util/actix_web_utils.rs
index f043ad8c..4cd95afd 100644
--- a/create-rust-app/src/util/actix_web_utils.rs
+++ b/create-rust-app/src/util/actix_web_utils.rs
@@ -1,9 +1,9 @@
+use super::template_utils::SinglePageApplication;
+use crate::util::template_utils::{to_template_name, DEFAULT_TEMPLATE, TEMPLATES};
 use actix_files::NamedFile;
-use actix_web::{HttpRequest, HttpResponse, Scope, web};
 use actix_web::http::StatusCode;
+use actix_web::{web, HttpRequest, HttpResponse, Scope};
 use tera::Context;
-use super::template_utils::SinglePageApplication;
-use crate::util::template_utils::{DEFAULT_TEMPLATE, TEMPLATES, to_template_name};
 
 /// 'route': the route where the SPA should be served from, for example: "/app"
 /// 'view': the view which renders the SPA, for example: "spa/index.html"
@@ -15,13 +15,18 @@ pub fn render_single_page_application(route: &str, view: &str) -> Scope {
 
     actix_web::web::scope(&format!("/{}{{tail:(/.*)?}}", route))
         .app_data(Data::new(SinglePageApplication {
-            view_name: view.to_string()
+            view_name: view.to_string(),
         }))
         .route("", web::get().to(render_spa_handler))
 }
 
-async fn render_spa_handler(req: HttpRequest, spa_info: web::Data<SinglePageApplication>) -> HttpResponse {
-    let content = TEMPLATES.render(spa_info.view_name.as_str(), &Context::new()).unwrap();
+async fn render_spa_handler(
+    req: HttpRequest,
+    spa_info: web::Data<SinglePageApplication>,
+) -> HttpResponse {
+    let content = TEMPLATES
+        .render(spa_info.view_name.as_str(), &Context::new())
+        .unwrap();
     template_response(content)
 }
 
@@ -38,22 +43,24 @@ pub async fn render_views(req: HttpRequest) -> HttpResponse {
     let mut content_result = TEMPLATES.render(template_path, &Context::new());
 
     if content_result.is_err() {
-        #[cfg(debug_assertions)] {
+        #[cfg(debug_assertions)]
+        {
             // dev asset serving
             let asset_path = &format!("./frontend{path}");
             if std::path::PathBuf::from(asset_path).is_file() {
                 println!("ASSET_FILE {path} => {asset_path}");
-                return NamedFile::open(asset_path).unwrap().into_response(&req)
+                return NamedFile::open(asset_path).unwrap().into_response(&req);
             }
 
             let public_path = &format!("./frontend/public{path}");
             if std::path::PathBuf::from(public_path).is_file() {
                 println!("PUBLIC_FILE {path} => {public_path}");
-                return NamedFile::open(public_path).unwrap().into_response(&req)
+                return NamedFile::open(public_path).unwrap().into_response(&req);
             }
         }
 
-        #[cfg(not(debug_assertions))] {
+        #[cfg(not(debug_assertions))]
+        {
             // production asset serving
             let static_path = &format!("./frontend/dist{path}");
             if std::path::PathBuf::from(static_path).is_file() {
@@ -65,7 +72,7 @@ pub async fn render_views(req: HttpRequest) -> HttpResponse {
         template_path = DEFAULT_TEMPLATE;
         if content_result.is_err() {
             // default template doesn't exist -- return 404 not found
-            return HttpResponse::NotFound().finish()
+            return HttpResponse::NotFound().finish();
         }
     }
 
@@ -78,7 +85,8 @@ pub async fn render_views(req: HttpRequest) -> HttpResponse {
 
 fn template_response(content: String) -> HttpResponse {
     let mut content = content;
-    #[cfg(debug_assertions)] {
+    #[cfg(debug_assertions)]
+    {
         let inject: &str = r##"
         <!-- development mode -->
         <script type="module">
diff --git a/create-rust-app/src/util/mod.rs b/create-rust-app/src/util/mod.rs
index e6eb30f7..6a6f9163 100644
--- a/create-rust-app/src/util/mod.rs
+++ b/create-rust-app/src/util/mod.rs
@@ -18,4 +18,4 @@ pub use poem_utils::*;
 /// expose template_utils for all backends.
 mod template_utils;
 
-pub mod net;
\ No newline at end of file
+pub mod net;
diff --git a/create-rust-app/src/util/net.rs b/create-rust-app/src/util/net.rs
index b0d68831..834370b4 100644
--- a/create-rust-app/src/util/net.rs
+++ b/create-rust-app/src/util/net.rs
@@ -3,7 +3,7 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, TcpListener, ToSo
 fn test_bind<A: ToSocketAddrs>(addr: A) -> bool {
     match TcpListener::bind(addr).map(|t| t.local_addr().is_ok()) {
         Ok(result) => result,
-        Err(_) => false
+        Err(_) => false,
     }
 }
 
diff --git a/create-rust-app/src/util/poem_utils.rs b/create-rust-app/src/util/poem_utils.rs
index 4216af79..37307974 100644
--- a/create-rust-app/src/util/poem_utils.rs
+++ b/create-rust-app/src/util/poem_utils.rs
@@ -1,10 +1,10 @@
 use http::{StatusCode, Uri};
-use poem::{Body, EndpointExt, handler, IntoResponse, Response, Route};
 use poem::middleware::{AddData, AddDataEndpoint};
-use poem::web::{Data};
+use poem::web::Data;
+use poem::{handler, Body, EndpointExt, IntoResponse, Response, Route};
 use tera::Context;
 
-use crate::util::template_utils::{DEFAULT_TEMPLATE, TEMPLATES, to_template_name};
+use crate::util::template_utils::{to_template_name, DEFAULT_TEMPLATE, TEMPLATES};
 
 use super::template_utils::SinglePageApplication;
 
@@ -18,17 +18,18 @@ pub fn render_single_page_application(view: &str) -> AddDataEndpoint<Route, Sing
     Route::new()
         .at("*", poem::get(render_spa_handler))
         .with(AddData::new(SinglePageApplication {
-            view_name: view.to_string()
+            view_name: view.to_string(),
         }))
 }
 
 #[handler]
 async fn render_spa_handler(spa_info: Data<&SinglePageApplication>) -> impl IntoResponse {
-    let content = TEMPLATES.render(spa_info.view_name.as_str(), &Context::new()).unwrap();
+    let content = TEMPLATES
+        .render(spa_info.view_name.as_str(), &Context::new())
+        .unwrap();
     template_response(content)
 }
 
-
 #[handler]
 pub async fn render_views(uri: &Uri) -> impl IntoResponse {
     let path = uri.path();
@@ -43,7 +44,8 @@ pub async fn render_views(uri: &Uri) -> impl IntoResponse {
     let mut content_result = TEMPLATES.render(template_path, &Context::new());
 
     if content_result.is_err() {
-        #[cfg(debug_assertions)] {
+        #[cfg(debug_assertions)]
+        {
             // dev asset serving
             let asset_path = &format!("./frontend{path}");
             if std::path::PathBuf::from(asset_path).is_file() {
@@ -60,7 +62,8 @@ pub async fn render_views(uri: &Uri) -> impl IntoResponse {
             }
         }
 
-        #[cfg(not(debug_assertions))] {
+        #[cfg(not(debug_assertions))]
+        {
             // production asset serving
             let static_path = &format!("./frontend/dist{path}");
             if std::path::PathBuf::from(static_path).is_file() {
@@ -85,7 +88,8 @@ pub async fn render_views(uri: &Uri) -> impl IntoResponse {
 
 fn template_response(content: String) -> Response {
     let mut content = content;
-    #[cfg(debug_assertions)] {
+    #[cfg(debug_assertions)]
+    {
         let inject: &str = r##"
         <!-- development mode -->
         <script type="module">
@@ -115,8 +119,9 @@ async fn file_response(path: &String) -> Response {
     let file = tokio::fs::read(path).await.unwrap();
     let content_type = mime_guess::from_path(path).first_raw();
     let mut response = Response::builder();
-    if content_type.is_some() { response = response.content_type(content_type.unwrap()); }
+    if content_type.is_some() {
+        response = response.content_type(content_type.unwrap());
+    }
     response = response.status(StatusCode::OK);
     response.body(Body::from(file))
 }
-
diff --git a/create-rust-app/src/util/template_utils.rs b/create-rust-app/src/util/template_utils.rs
index 53378090..60b68911 100644
--- a/create-rust-app/src/util/template_utils.rs
+++ b/create-rust-app/src/util/template_utils.rs
@@ -1,10 +1,10 @@
-use std::collections::HashMap;
 use lazy_static::lazy_static;
+use std::collections::HashMap;
 use tera::Tera;
 
 #[derive(Clone)]
 pub struct SinglePageApplication {
-    pub view_name: String
+    pub view_name: String,
 }
 
 lazy_static! {
@@ -29,7 +29,11 @@ lazy_static! {
 pub const DEFAULT_TEMPLATE: &'static str = "index.html";
 pub fn to_template_name(request_path: &str) -> &'_ str {
     let request_path = request_path.strip_prefix("/").unwrap();
-    return if request_path.eq("") { DEFAULT_TEMPLATE } else { request_path }
+    return if request_path.eq("") {
+        DEFAULT_TEMPLATE
+    } else {
+        request_path
+    };
 }
 
 /// This implements the {{ bundle(name="index.tsx") }} function for our templates
@@ -37,38 +41,70 @@ struct InjectBundle;
 impl tera::Function for InjectBundle {
     fn call(&self, args: &HashMap<String, serde_json::Value>) -> tera::Result<serde_json::Value> {
         match args.get("name") {
-            Some(val) => return match tera::from_value::<String>(val.clone()) {
-                Ok(bundle_name) => {
-                    let inject: String;
-
-                    #[cfg(not(debug_assertions))] {
-                        let manifest_entry = VITE_MANIFEST.get(&format!("bundles/{bundle_name}"))
-                            .expect(&format!("could not get bundle `{bundle_name}`"));
-                        let entry_file = format!(r#"<script type="module" src="/{file}"></script>"#, file=manifest_entry.file);
-                        let css_files = manifest_entry.css.as_ref().unwrap_or(&vec![]).into_iter().map(|css_file| {
-                            format!(r#"<link rel="stylesheet" href="/{file}" />"#, file = css_file)
-                        }).collect::<Vec<String>>().join("\n");
-                        let dyn_entry_files = manifest_entry.dynamicImports.as_ref().unwrap_or(&vec![]).into_iter().map(|dyn_script_file| {
-                            // TODO: make this deferred or async -- look this up!~
-                            format!(r#"<script type="module" src="/{file}"></script>"#, file=dyn_script_file)
-                        }).collect::<Vec<String>>().join("\n");
-
-                        inject = format!(r##"
+            Some(val) => {
+                return match tera::from_value::<String>(val.clone()) {
+                    Ok(bundle_name) => {
+                        let inject: String;
+
+                        #[cfg(not(debug_assertions))]
+                        {
+                            let manifest_entry = VITE_MANIFEST
+                                .get(&format!("bundles/{bundle_name}"))
+                                .expect(&format!("could not get bundle `{bundle_name}`"));
+                            let entry_file = format!(
+                                r#"<script type="module" src="/{file}"></script>"#,
+                                file = manifest_entry.file
+                            );
+                            let css_files = manifest_entry
+                                .css
+                                .as_ref()
+                                .unwrap_or(&vec![])
+                                .into_iter()
+                                .map(|css_file| {
+                                    format!(
+                                        r#"<link rel="stylesheet" href="/{file}" />"#,
+                                        file = css_file
+                                    )
+                                })
+                                .collect::<Vec<String>>()
+                                .join("\n");
+                            let dyn_entry_files = manifest_entry
+                                .dynamicImports
+                                .as_ref()
+                                .unwrap_or(&vec![])
+                                .into_iter()
+                                .map(|dyn_script_file| {
+                                    // TODO: make this deferred or async -- look this up!~
+                                    format!(
+                                        r#"<script type="module" src="/{file}"></script>"#,
+                                        file = dyn_script_file
+                                    )
+                                })
+                                .collect::<Vec<String>>()
+                                .join("\n");
+
+                            inject = format!(
+                                r##"
                         <!-- production mode -->
                         {entry_file}
                         {css_files}
                         {dyn_entry_files}
-                        "##);
-                    }
-
-                    #[cfg(debug_assertions)] {
-                        inject = format!(r#"<script type="module" src="http://localhost:21012/bundles/{bundle_name}"></script>"#);
+                        "##
+                            );
+                        }
+
+                        #[cfg(debug_assertions)]
+                        {
+                            inject = format!(
+                                r#"<script type="module" src="http://localhost:21012/bundles/{bundle_name}"></script>"#
+                            );
+                        }
+
+                        Ok(tera::to_value(inject).unwrap())
                     }
-
-                    Ok(tera::to_value(inject).unwrap())
-                },
-                Err(_) => panic!("No bundle named '{:#?}'", val),
-            },
+                    Err(_) => panic!("No bundle named '{:#?}'", val),
+                };
+            }
             None => Err("oops".into()),
         }
     }
@@ -93,19 +129,21 @@ pub struct ViteManifestEntry {
     isEntry: Option<bool>,
 
     // If true, lazy-load this content
-    isDynamicEntry: Option<bool>
-
-    // src: String, /* => not necessary :) */
-    // assets: Option<Vec<String>>, /* => these will be served by the server! */
+    isDynamicEntry: Option<bool>, // src: String, /* => not necessary :) */
+                                  // assets: Option<Vec<String>>, /* => these will be served by the server! */
 }
 type ViteManifest = HashMap<String, ViteManifestEntry>;
 
-
 fn load_manifest_entries() -> ViteManifest {
     let mut manifest: ViteManifest = HashMap::new();
 
     use serde_json::Value;
-    let manifest_json = serde_json::from_str(std::fs::read_to_string(std::path::PathBuf::from("./frontend/dist/manifest.json")).unwrap().as_str()).unwrap();
+    let manifest_json = serde_json::from_str(
+        std::fs::read_to_string(std::path::PathBuf::from("./frontend/dist/manifest.json"))
+            .unwrap()
+            .as_str(),
+    )
+    .unwrap();
 
     match manifest_json {
         Value::Object(obj) => {
@@ -118,7 +156,7 @@ fn load_manifest_entries() -> ViteManifest {
                 manifest.insert(manifest_key.to_string(), manifest_entry);
             });
             // done parsing manifest
-        },
+        }
         _ => {
             panic!("invalid vite manifest (or perhaps the create-rust-app parser broke!)");
         }
diff --git a/create-rust-app_cli/src/content/cargo_toml.rs b/create-rust-app_cli/src/content/cargo_toml.rs
index da6f6ea2..954147c8 100644
--- a/create-rust-app_cli/src/content/cargo_toml.rs
+++ b/create-rust-app_cli/src/content/cargo_toml.rs
@@ -28,7 +28,10 @@ pub fn add_dependency(
         .unwrap()
         .as_table_mut()
         .unwrap();
-    deps_table.insert("replace_me".to_string(), toml::Value::String("123".to_string()));
+    deps_table.insert(
+        "replace_me".to_string(),
+        toml::Value::String("123".to_string()),
+    );
 
     let updated_toml = toml::to_string(&parsed_toml).unwrap();
     let updated_toml = updated_toml.replace("replace_me = \"123\"", dependency_entry);
@@ -37,4 +40,3 @@ pub fn add_dependency(
 
     Ok(())
 }
-
diff --git a/create-rust-app_cli/src/content/mod.rs b/create-rust-app_cli/src/content/mod.rs
index 9ef6c297..f6b1cd96 100644
--- a/create-rust-app_cli/src/content/mod.rs
+++ b/create-rust-app_cli/src/content/mod.rs
@@ -1,9 +1,8 @@
+pub mod cargo_toml;
 ///
 /// This package contains helper functions which create content in create-rust-app projects.
 ///
-
 pub mod migration;
-pub mod service;
 pub mod model;
-pub mod cargo_toml;
 pub mod project;
+pub mod service;
diff --git a/create-rust-app_cli/src/content/project.rs b/create-rust-app_cli/src/content/project.rs
index efaa4b2e..5ec3ee9e 100644
--- a/create-rust-app_cli/src/content/project.rs
+++ b/create-rust-app_cli/src/content/project.rs
@@ -1,6 +1,8 @@
+use crate::content::cargo_toml::add_dependency;
 use crate::utils::git;
 use crate::utils::logger;
-use crate::content::cargo_toml::add_dependency;
+use crate::BackendDatabase;
+use crate::BackendFramework;
 use anyhow::Result;
 use console::style;
 use dialoguer::{theme::ColorfulTheme, Confirm, Input};
@@ -8,9 +10,8 @@ use inflector::Inflector;
 use rust_embed::RustEmbed;
 use std::path::PathBuf;
 use std::time::Duration;
-use walkdir::WalkDir;
 use update_informer::{registry, Check};
-use crate::BackendFramework;
+use walkdir::WalkDir;
 
 #[derive(RustEmbed)]
 #[folder = "template"]
@@ -70,11 +71,12 @@ fn add_bins_to_cargo_toml(project_dir: &std::path::PathBuf) -> Result<(), std::i
         None => panic!("Could not determine project name from generated Cargo.toml"),
     };
 
-    if !found_project_name { logger::error("Failed to find the project's package name! Defaulting main executable name to 'app'. Feel free to change it in `Cargo.toml`."); }
+    if !found_project_name {
+        logger::error("Failed to find the project's package name! Defaulting main executable name to 'app'. Feel free to change it in `Cargo.toml`.");
+    }
 
     let updated_toml = toml::to_string(&parsed_toml).unwrap();
 
-
     let append_to_toml = format!(
         r#"
 [[bin]]
@@ -107,10 +109,14 @@ debug-assertions=true
 
 pub struct CreationOptions {
     pub cra_enabled_features: Vec<String>,
-    pub backend_framework: BackendFramework
+    pub backend_framework: BackendFramework,
+    pub backend_database: BackendDatabase,
 }
 
-pub fn remove_non_framework_files(project_dir: &PathBuf, framework: BackendFramework) -> Result<()> {
+pub fn remove_non_framework_files(
+    project_dir: &PathBuf,
+    framework: BackendFramework,
+) -> Result<()> {
     /* Choose framework-specific files */
     for entry in WalkDir::new(project_dir) {
         let entry = entry.unwrap();
@@ -124,7 +130,12 @@ pub fn remove_non_framework_files(project_dir: &PathBuf, framework: BackendFrame
                 std::fs::remove_file(file)?;
             };
             if framework == BackendFramework::ActixWeb {
-                let dest = file.with_extension(file.extension().unwrap().to_string_lossy().replace("+actix_web", ""));
+                let dest = file.with_extension(
+                    file.extension()
+                        .unwrap()
+                        .to_string_lossy()
+                        .replace("+actix_web", ""),
+                );
                 logger::rename_file_msg(&format!("{:#?}", &file), &format!("{:#?}", &dest));
                 std::fs::rename(file, dest)?;
             };
@@ -134,7 +145,59 @@ pub fn remove_non_framework_files(project_dir: &PathBuf, framework: BackendFrame
                 std::fs::remove_file(file)?;
             };
             if framework == BackendFramework::Poem {
-                let dest = file.with_extension(file.extension().unwrap().to_string_lossy().replace("+poem", ""));
+                let dest = file.with_extension(
+                    file.extension()
+                        .unwrap()
+                        .to_string_lossy()
+                        .replace("+poem", ""),
+                );
+                logger::rename_file_msg(&format!("{:#?}", &file), &format!("{:#?}", &dest));
+                std::fs::rename(file, dest)?;
+            };
+        }
+    }
+
+    Ok(())
+}
+
+pub fn remove_non_database_files(
+    project_dir: &PathBuf,
+    database: BackendDatabase,
+) -> Result<()> {
+    /* Choose framework-specific files */
+    for entry in WalkDir::new(project_dir) {
+        let entry = entry.unwrap();
+
+        let file = entry.path();
+        let path = file.clone().to_str().unwrap().to_string();
+
+        if path.ends_with("+database_postgres") {
+            if database != BackendDatabase::Postgres {
+                logger::remove_file_msg(&format!("{:#?}", &file));
+                std::fs::remove_file(file)?;
+            };
+            if database == BackendDatabase::Postgres{
+                let dest = file.with_extension(
+                    file.extension()
+                        .unwrap()
+                        .to_string_lossy()
+                        .replace("+database_postgres", ""),
+                );
+                logger::rename_file_msg(&format!("{:#?}", &file), &format!("{:#?}", &dest));
+                std::fs::rename(file, dest)?;
+            };
+        } else if path.ends_with("+database_sqlite") {
+            if database != BackendDatabase::Sqlite {
+                logger::remove_file_msg(&format!("{:#?}", &file));
+                std::fs::remove_file(file)?;
+            };
+            if database == BackendDatabase::Sqlite {
+                let dest = file.with_extension(
+                    file.extension()
+                        .unwrap()
+                        .to_string_lossy()
+                        .replace("+database_sqlite", ""),
+                );
                 logger::rename_file_msg(&format!("{:#?}", &file), &format!("{:#?}", &dest));
                 std::fs::rename(file, dest)?;
             };
@@ -222,34 +285,83 @@ pub fn create(project_name: &str, creation_options: CreationOptions) -> Result<(
 
     add_bins_to_cargo_toml(&project_dir)?;
 
-
     let framework = creation_options.backend_framework;
+    let database = creation_options.backend_database;
     let cra_enabled_features = creation_options.cra_enabled_features;
 
-    let mut enabled_features: String = cra_enabled_features.iter().map(|f| format!("\"{}\"", f)).collect::<Vec<String>>().join(", ");
-    if !cra_enabled_features.is_empty() { enabled_features = ", features=[".to_string() + &enabled_features + "]"; }
+    let mut enabled_features: String = cra_enabled_features
+        .iter()
+        .map(|f| format!("\"{}\"", f))
+        .collect::<Vec<String>>()
+        .join(", ");
+    if !cra_enabled_features.is_empty() {
+        enabled_features = ", features=[".to_string() + &enabled_features + "]";
+    }
 
     match framework {
         BackendFramework::ActixWeb => {
             add_dependency(&project_dir, "actix-files", r#"actix-files = "0.6.0""#)?;
             add_dependency(&project_dir, "actix-http", r#"actix-http = "3.0.0""#)?;
             add_dependency(&project_dir, "actix-web", r#"actix-web = "4.0.1""#)?;
-            add_dependency(&project_dir, "actix-multipart", r#"actix-multipart = "0.4.0""#)?;
-            add_dependency(&project_dir, "tokio", r#"tokio = { version = "1", features = ["full"] }"#)?;
-        },
+            add_dependency(
+                &project_dir,
+                "actix-multipart",
+                r#"actix-multipart = "0.4.0""#,
+            )?;
+            add_dependency(
+                &project_dir,
+                "tokio",
+                r#"tokio = { version = "1", features = ["full"] }"#,
+            )?;
+        }
         BackendFramework::Poem => {
-            add_dependency(&project_dir, "poem", r#"poem = { version="1.3.18", features=["anyhow", "cookie", "static-files", "multipart"] }"#)?;
-            add_dependency(&project_dir, "tokio", r#"tokio = { version = "1.15.0", features = ["rt-multi-thread", "macros"] }"#)?;
-            add_dependency(&project_dir, "tracing_subscriber", r#"tracing-subscriber = "0.3.7""#)?;
+            add_dependency(
+                &project_dir,
+                "poem",
+                r#"poem = { version="1.3.18", features=["anyhow", "cookie", "static-files", "multipart"] }"#,
+            )?;
+            add_dependency(
+                &project_dir,
+                "tokio",
+                r#"tokio = { version = "1.15.0", features = ["rt-multi-thread", "macros"] }"#,
+            )?;
+            add_dependency(
+                &project_dir,
+                "tracing_subscriber",
+                r#"tracing-subscriber = "0.3.7""#,
+            )?;
         }
     }
     add_dependency(&project_dir, "futures-util", r#"futures-util = "0.3.21""#)?;
-    add_dependency(&project_dir, "serde", r#"serde = { version = "1.0.133", features = ["derive"] }"#)?;
+    add_dependency(
+        &project_dir,
+        "serde",
+        r#"serde = { version = "1.0.133", features = ["derive"] }"#,
+    )?;
     add_dependency(&project_dir, "serde_json", r#"serde_json = "1.0.79""#)?;
-    add_dependency(&project_dir, "chrono", r#"chrono = { version = "0.4.19", features = ["serde"] }"#)?;
+    add_dependency(
+        &project_dir,
+        "chrono",
+        r#"chrono = { version = "0.4.19", features = ["serde"] }"#,
+    )?;
     add_dependency(&project_dir, "tsync", r#"tsync = "1.2.1""#)?;
-    add_dependency(&project_dir, "diesel", r#"diesel = { version="2.0.0-rc.1", default-features = false, features = ["postgres", "r2d2", "chrono"] }"#)?;
-    add_dependency(&project_dir, "create-rust-app", &format!("create-rust-app = {{version=\"{version}\"{enabled_features}}}", version= get_current_cra_lib_version(), enabled_features=enabled_features))?;
+    add_dependency(
+        &project_dir,
+        "diesel",
+        &format!(r#"diesel = {{ version="2.0.0-rc.1", default-features = false, features = ["{db}", "r2d2", "chrono"] }}"#, db = match database {
+            BackendDatabase::Postgres => "postgres",
+            BackendDatabase::Sqlite => "sqlite",
+        }),
+    )?;
+    add_dependency(
+        &project_dir,
+        "create-rust-app",
+        &format!(
+            "create-rust-app = {{version=\"{version}\"{enabled_features}}}",
+            version = get_current_cra_lib_version(),
+            enabled_features = enabled_features
+        ),
+    )?;
 
     /*
         Populate with project files
@@ -267,6 +379,44 @@ pub fn create(project_name: &str, creation_options: CreationOptions) -> Result<(
     }
 
     remove_non_framework_files(&project_dir, framework)?;
+    remove_non_database_files(&project_dir, database)?;
+
+    if database == BackendDatabase::Sqlite {
+        // for sqlite, we don't want the initial diesel setup or database timezone adjustment
+        let mut mig1 = PathBuf::from(&project_dir);
+        mig1.push("migrations");
+        let mut mig2 = mig1.clone();
+        let mut mig3 = mig1.clone();
+        let mut mig0 = mig1.clone();
+        mig1.push("00000000000000_diesel_initial_setup");
+        mig2.push("00000000000001_utc");
+        mig3.push("00000000000002_todos");
+        mig0.push("00000000000099_todos");
+        std::fs::remove_dir(mig1)?;
+        std::fs::remove_dir(mig2)?;
+        std::fs::create_dir(&mig0)?;
+        let mut up = mig3.clone();
+        up.push("up.sql");
+        let mut down = mig3.clone();
+        down.push("down.sql");
+        let mut new_up = mig0.clone();
+        new_up.push("up.sql");
+        let mut new_down = mig0.clone();
+        new_down.push("down.sql");
+        std::fs::rename(up, new_up)?;
+        std::fs::rename(down, new_down)?;
+        std::fs::remove_dir(mig3)?;
+
+        // also, let's update the env files
+        let mut env_example_file = PathBuf::from(&project_dir);
+        let mut env_file = PathBuf::from(&project_dir);
+        env_example_file.push(".env.example");
+        env_file.push(".env");
+        let contents = std::fs::read_to_string(&env_example_file)?;
+        let contents = contents.replace("postgres://postgres:postgres@localhost/database", "dev.sqlite");
+        std::fs::write(env_example_file, contents.clone())?;
+        std::fs::write(env_file, contents.clone())?;
+    }
 
     /*
         Finalize; create the initial commit.
@@ -412,18 +562,21 @@ pub fn create_resource(backend: BackendFramework, resource_name: &str) -> Result
     Ok(())
 }
 
-pub fn check_cli_version() -> Result<()>{
-  let name = env!("CARGO_PKG_NAME");
-  let version = env!("CARGO_PKG_VERSION");
-  let informer = update_informer::new(registry::Crates, name, version)
-      .timeout(Duration::from_secs(2))
-      .interval(Duration::ZERO);
-  if let Some(new_version) = informer.check_version().ok().flatten()  {
-    logger::message(&style(&format!("You are running `{name}` v{version}, which is behind the latest release ({new_version}).")).yellow().to_string());
-    logger::message(&format!("If you want to update, try: {}", style("cargo install --force create-rust-app_cli").yellow()));
-  } else {
-    // we aren't sure whether the version check succeeded here (it could have been timed out)
-    logger::message(&format!("v{version}"));
-  }
-  Ok(())
+pub fn check_cli_version() -> Result<()> {
+    let name = env!("CARGO_PKG_NAME");
+    let version = env!("CARGO_PKG_VERSION");
+    let informer = update_informer::new(registry::Crates, name, version)
+        .timeout(Duration::from_secs(2))
+        .interval(Duration::ZERO);
+    if let Some(new_version) = informer.check_version().ok().flatten() {
+        logger::message(&style(&format!("You are running `{name}` v{version}, which is behind the latest release ({new_version}).")).yellow().to_string());
+        logger::message(&format!(
+            "If you want to update, try: {}",
+            style("cargo install --force create-rust-app_cli").yellow()
+        ));
+    } else {
+        // we aren't sure whether the version check succeeded here (it could have been timed out)
+        logger::message(&format!("v{version}"));
+    }
+    Ok(())
 }
diff --git a/create-rust-app_cli/src/content/service.rs b/create-rust-app_cli/src/content/service.rs
index 71caef12..83dc30f8 100644
--- a/create-rust-app_cli/src/content/service.rs
+++ b/create-rust-app_cli/src/content/service.rs
@@ -1,9 +1,9 @@
+use crate::logger::register_service_msg;
+use crate::BackendFramework;
 use anyhow::Result;
 use indoc::indoc;
 use inflector::Inflector;
 use std::path::PathBuf;
-use crate::BackendFramework;
-use crate::logger::register_service_msg;
 
 struct Service {
     pub config: ServiceConfig,
@@ -15,10 +15,15 @@ struct ServiceConfig {
     pub file_name: String,
 }
 
-pub fn create(backend: BackendFramework, resource_name: &str, service_api_fn: &str, base_endpoint_path: &str) -> Result<()> {
+pub fn create(
+    backend: BackendFramework,
+    resource_name: &str,
+    service_api_fn: &str,
+    base_endpoint_path: &str,
+) -> Result<()> {
     let resource = match backend {
         BackendFramework::ActixWeb => generate_actix(resource_name),
-        BackendFramework::Poem => generate_poem(resource_name)
+        BackendFramework::Poem => generate_poem(resource_name),
     };
 
     crate::fs::add_rust_file(
@@ -30,10 +35,17 @@ pub fn create(backend: BackendFramework, resource_name: &str, service_api_fn: &s
     match backend {
         BackendFramework::ActixWeb => {
             let name = resource.config.file_name.as_str();
-            let service_entry = &format!("services::{}::endpoints(web::scope(\"{}\"))", name, base_endpoint_path);
+            let service_entry = &format!(
+                "services::{}::endpoints(web::scope(\"{}\"))",
+                name, base_endpoint_path
+            );
             register_actix(name, service_entry)?;
-        },
-        BackendFramework::Poem => register_poem(&resource.config.file_name, service_api_fn, base_endpoint_path)?
+        }
+        BackendFramework::Poem => register_poem(
+            &resource.config.file_name,
+            service_api_fn,
+            base_endpoint_path,
+        )?,
     };
 
     Ok(())
@@ -234,13 +246,23 @@ fn generate_actix(service_name: &str) -> Service {
 
 /// use fs::replace instead and also fs::append for the services/mod.rs entry
 // #[deprecated]
-pub fn register_poem(name: &str, service_api_fn: &str, service_base_endpoint_path: &str) -> Result<()> {
+pub fn register_poem(
+    name: &str,
+    service_api_fn: &str,
+    service_base_endpoint_path: &str,
+) -> Result<()> {
     register_service_msg(name);
     let main_file_path = PathBuf::from("backend/main.rs");
     if main_file_path.exists() && main_file_path.is_file() {
         let mut main_file_contents = std::fs::read_to_string(&main_file_path)?;
 
-        main_file_contents = main_file_contents.replace("let mut api_routes = Route::new();", &format!("let mut api_routes = Route::new();\n\t\tapi_routes = api_routes.nest(\"{}\", {});", service_base_endpoint_path, service_api_fn));
+        main_file_contents = main_file_contents.replace(
+            "let mut api_routes = Route::new();",
+            &format!(
+                "let mut api_routes = Route::new();\n\t\tapi_routes = api_routes.nest(\"{}\", {});",
+                service_base_endpoint_path, service_api_fn
+            ),
+        );
         std::fs::write(main_file_path, main_file_contents)?;
     }
 
@@ -256,11 +278,14 @@ pub fn register_actix(name: &str, service: &str) -> Result<()> {
         let mut main_file_contents = std::fs::read_to_string(&main_file_path)?;
         main_file_contents = main_file_contents.replace(
             r#"let mut api_scope = web::scope("/api");"#,
-            &format!(r#"let mut api_scope = web::scope("/api");
-        api_scope = api_scope.service({});"#, service)
+            &format!(
+                r#"let mut api_scope = web::scope("/api");
+        api_scope = api_scope.service({});"#,
+                service
+            ),
         );
         std::fs::write(main_file_path, main_file_contents)?;
     }
 
     Ok(())
-}
\ No newline at end of file
+}
diff --git a/create-rust-app_cli/src/main.rs b/create-rust-app_cli/src/main.rs
index 41963022..17d383dd 100644
--- a/create-rust-app_cli/src/main.rs
+++ b/create-rust-app_cli/src/main.rs
@@ -1,23 +1,30 @@
 extern crate inflector;
 
 mod content;
-mod utils;
 mod plugins;
 mod qsync;
+mod utils;
 
 use anyhow::Result;
 use std::path::PathBuf;
 use structopt::StructOpt;
 
+use crate::project::CreationOptions;
 use console::Term;
-use dialoguer::{Input, MultiSelect, Select, theme::ColorfulTheme};
 use content::project;
+use dialoguer::{theme::ColorfulTheme, Input, MultiSelect, Select};
 use utils::{fs, logger};
-use crate::project::CreationOptions;
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum BackendFramework {
-    ActixWeb, Poem
+    ActixWeb,
+    Poem,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum BackendDatabase {
+    Postgres,
+    Sqlite,
 }
 
 #[derive(StructOpt, Debug)]
@@ -76,26 +83,34 @@ fn main() -> Result<()> {
     if !is_rust_project_directory {
         let create_opts = CreateOpt::from_args();
 
+        logger::message("Select a database to use:");
+        logger::message("Use UP/DOWN arrows to navigate and SPACE or ENTER to confirm.");
+        let items = vec!["postgres", "sqlite"];
+        let selection = Select::with_theme(&ColorfulTheme::default())
+            .items(&items)
+            .default(0)
+            .interact_on_opt(&Term::stderr())?;
+
+        let backend_database: BackendDatabase = match selection {
+            Some(0) => BackendDatabase::Postgres,
+            Some(1) => BackendDatabase::Sqlite,
+            _ => panic!("Fatal: Unknown backend framework specified."),
+        };
+
         logger::message("Select a rust backend framework to use:");
         logger::message("Use UP/DOWN arrows to navigate and SPACE or ENTER to confirm.");
         let items = vec!["actix-web", "poem"];
         let selection = Select::with_theme(&ColorfulTheme::default())
-                .items(&items)
-                .default(0)
-                .interact_on_opt(&Term::stderr())?;
+            .items(&items)
+            .default(0)
+            .interact_on_opt(&Term::stderr())?;
 
         let backend_framework: BackendFramework = match selection {
             Some(0) => BackendFramework::ActixWeb,
             Some(1) => BackendFramework::Poem,
-            _ => panic!("Fatal: Unknown backend framework specified.")
+            _ => panic!("Fatal: Unknown backend framework specified."),
         };
 
-        // let valid_frameworks = vec!["actix_web", "poem"];
-        //
-        // if !valid_frameworks.contains(&backend_framework.as_str()) {
-        //     panic!("Invalid framework given. Choose one of: {:#?}", valid_frameworks);
-        // }
-
         let project_name = create_opts.target;
 
         if project_name.len() == 0 {
@@ -112,7 +127,7 @@ fn main() -> Result<()> {
             "Container Plugin: dockerize your app",
             "Development Plugin: adds dev warnings and an admin portal",
             "Storage Plugin: adds S3 file storage capabilities",
-            "GraphQL Plugin: bootstraps a GraphQL setup including a playground"
+            "GraphQL Plugin: bootstraps a GraphQL setup including a playground",
         ];
         let chosen: Vec<usize> = MultiSelect::with_theme(&ColorfulTheme::default())
             .items(&items)
@@ -125,26 +140,45 @@ fn main() -> Result<()> {
         let add_plugin_storage = chosen.iter().position(|x| *x == 3).is_some();
         let add_plugin_graphql = chosen.iter().position(|x| *x == 4).is_some();
 
-        let mut features: Vec<String> = vec!();
-        if add_plugin_dev { features.push("plugin_dev".to_string()); }
-        if add_plugin_auth { features.push("plugin_auth".to_string()); }
-        if add_plugin_container { features.push("plugin_container".to_string()); }
-        if add_plugin_storage { features.push("plugin_storage".to_string()); }
-        if add_plugin_graphql { features.push("plugin_graphql".to_string()); }
+        let mut features: Vec<String> = vec![];
+        if add_plugin_dev {
+            features.push("plugin_dev".to_string());
+        }
+        if add_plugin_auth {
+            features.push("plugin_auth".to_string());
+        }
+        if add_plugin_container {
+            features.push("plugin_container".to_string());
+        }
+        if add_plugin_storage {
+            features.push("plugin_storage".to_string());
+        }
+        if add_plugin_graphql {
+            features.push("plugin_graphql".to_string());
+        }
+        features.push(match backend_database {
+            BackendDatabase::Postgres => "database_postgres".to_string(),
+            BackendDatabase::Sqlite => "database_sqlite".to_string(),
+        });
         features.push(match backend_framework {
             BackendFramework::ActixWeb => "backend_actix-web".to_string(),
-            BackendFramework::Poem => "backend_poem".to_string()
+            BackendFramework::Poem => "backend_poem".to_string(),
         });
 
-        project::create(project_name.as_ref(), CreationOptions {
-            cra_enabled_features: features,
-            backend_framework
-        })?;
+        project::create(
+            project_name.as_ref(),
+            CreationOptions {
+                cra_enabled_features: features,
+                backend_framework,
+                backend_database,
+            },
+        )?;
 
         let mut project_dir = PathBuf::from(".");
         project_dir.push(project_name);
         // !
-        std::env::set_current_dir(project_dir.clone()).expect(&format!("Unable to change into {:#?}", project_dir.clone()));
+        std::env::set_current_dir(project_dir.clone())
+            .expect(&format!("Unable to change into {:#?}", project_dir.clone()));
 
         //
         // Note: we're in the project dir from here on out
@@ -153,18 +187,29 @@ fn main() -> Result<()> {
         let install_config = plugins::InstallConfig {
             project_dir: PathBuf::from("."),
             backend_framework,
+            backend_database,
             plugin_dev: add_plugin_dev,
             plugin_auth: add_plugin_auth,
             plugin_container: add_plugin_container,
             plugin_storage: add_plugin_storage,
-            plugin_graphql: add_plugin_graphql
+            plugin_graphql: add_plugin_graphql,
         };
 
-        if add_plugin_auth { plugins::install(plugins::auth::Auth {}, install_config.clone())?; }
-        if add_plugin_container { plugins::install(plugins::container::Container {}, install_config.clone())?; }
-        if add_plugin_dev { plugins::install(plugins::dev::Dev {}, install_config.clone())?; }
-        if add_plugin_storage { plugins::install(plugins::storage::Storage {}, install_config.clone())?; }
-        if add_plugin_graphql { plugins::install(plugins::graphql::GraphQL {}, install_config.clone())?; }
+        if add_plugin_auth {
+            plugins::install(plugins::auth::Auth {}, install_config.clone())?;
+        }
+        if add_plugin_container {
+            plugins::install(plugins::container::Container {}, install_config.clone())?;
+        }
+        if add_plugin_dev {
+            plugins::install(plugins::dev::Dev {}, install_config.clone())?;
+        }
+        if add_plugin_storage {
+            plugins::install(plugins::storage::Storage {}, install_config.clone())?;
+        }
+        if add_plugin_graphql {
+            plugins::install(plugins::graphql::GraphQL {}, install_config.clone())?;
+        }
 
         // cd into project dir and make a copy of the env file
         let example_env_file = PathBuf::from("./.env.example");
@@ -196,7 +241,11 @@ fn main() -> Result<()> {
         // return Ok(());
 
         let update_opts = UpdateOpt::from_args();
-        let items = vec!["Generate react-query hooks (beta)", "Add a model & service (beta)", "Cancel"];
+        let items = vec![
+            "Generate react-query hooks (beta)",
+            "Add a model & service (beta)",
+            "Cancel",
+        ];
 
         let selection = if update_opts.query_sync {
             Some(0)
@@ -229,7 +278,9 @@ fn main() -> Result<()> {
                         }
 
                         logger::message("Which backend framework are you using?");
-                        logger::message("Use UP/DOWN arrows to navigate and SPACE or ENTER to confirm.");
+                        logger::message(
+                            "Use UP/DOWN arrows to navigate and SPACE or ENTER to confirm.",
+                        );
                         let items = vec!["actix_web", "poem"];
                         let selection = Select::with_theme(&ColorfulTheme::default())
                             .items(&items)
@@ -239,7 +290,7 @@ fn main() -> Result<()> {
                         let backend_framework: BackendFramework = match selection {
                             Some(0) => BackendFramework::ActixWeb,
                             Some(1) => BackendFramework::Poem,
-                            _ => panic!("Fatal: Unknown backend framework specified.")
+                            _ => panic!("Fatal: Unknown backend framework specified."),
                         };
                         project::create_resource(backend_framework, resource_name.as_ref())?;
                         std::process::exit(0);
diff --git a/create-rust-app_cli/src/plugins/auth.rs b/create-rust-app_cli/src/plugins/auth.rs
index 3b19df62..ef6e4b1b 100644
--- a/create-rust-app_cli/src/plugins/auth.rs
+++ b/create-rust-app_cli/src/plugins/auth.rs
@@ -2,10 +2,10 @@ use crate::plugins::InstallConfig;
 use crate::plugins::Plugin;
 use crate::utils::fs;
 use crate::utils::logger::add_file_msg;
+use crate::{BackendDatabase, BackendFramework};
 use anyhow::Result;
 use indoc::indoc;
 use rust_embed::RustEmbed;
-use crate::BackendFramework;
 
 pub struct Auth {}
 
@@ -97,7 +97,8 @@ import { ResetPage } from './containers/ResetPage'"#,
 
         crate::content::migration::create(
             "plugin_auth",
-            indoc! {r#"
+            match install_config.backend_database {
+                BackendDatabase::Postgres => indoc! {r#"
       CREATE TABLE users (
         id SERIAL PRIMARY KEY,
         email TEXT NOT NULL,
@@ -141,6 +142,45 @@ import { ResetPage } from './containers/ResetPage'"#,
         PRIMARY KEY (role, permission)
       );
     "#},
+                BackendDatabase::Sqlite => indoc! {r#"
+      CREATE TABLE users (
+        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+        email TEXT NOT NULL,
+        hash_password TEXT NOT NULL,
+        activated BOOLEAN NOT NULL DEFAULT FALSE,
+        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+      );
+
+      CREATE TABLE user_sessions (
+        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+        user_id INTEGER NOT NULL REFERENCES users(id),
+        refresh_token TEXT NOT NULL,
+        device TEXT,
+        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+      );
+
+      CREATE TABLE user_permissions (
+        user_id INTEGER NOT NULL REFERENCES users(id),
+        permission TEXT NOT NULL,
+        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+        PRIMARY KEY (user_id, permission)
+      );
+
+      CREATE TABLE user_roles (
+        user_id INTEGER NOT NULL REFERENCES users(id),
+        role TEXT NOT NULL,
+        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+        PRIMARY KEY (user_id, role)
+      );
+
+      CREATE TABLE role_permissions (
+        role TEXT NOT NULL,
+        permission TEXT NOT NULL,
+        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+        PRIMARY KEY (role, permission)
+      );
+    "#}
+            },
             indoc! {r#"
       DROP TABLE users CASCADE ALL;
       DROP TABLE user_sessions CASCADE ALL;
@@ -151,12 +191,10 @@ import { ResetPage } from './containers/ResetPage'"#,
         )?;
 
         match install_config.backend_framework {
-            BackendFramework::ActixWeb => {
-                crate::content::service::register_actix(
-                    "auth",
-                    r#"create_rust_app::auth::endpoints(web::scope("/auth"))"#
-                )?
-            },
+            BackendFramework::ActixWeb => crate::content::service::register_actix(
+                "auth",
+                r#"create_rust_app::auth::endpoints(web::scope("/auth"))"#,
+            )?,
             BackendFramework::Poem => crate::content::service::register_poem(
                 "auth",
                 "create_rust_app::auth::api()",
diff --git a/create-rust-app_cli/src/plugins/container.rs b/create-rust-app_cli/src/plugins/container.rs
index f8ff2dab..c90a4d90 100644
--- a/create-rust-app_cli/src/plugins/container.rs
+++ b/create-rust-app_cli/src/plugins/container.rs
@@ -1,7 +1,7 @@
-use crate::utils::fs;
-use crate::utils::logger::add_file_msg;
 use crate::plugins::InstallConfig;
 use crate::plugins::Plugin;
+use crate::utils::fs;
+use crate::utils::logger::add_file_msg;
 use anyhow::Result;
 use rust_embed::RustEmbed;
 
diff --git a/create-rust-app_cli/src/plugins/dev.rs b/create-rust-app_cli/src/plugins/dev.rs
index 9a8beb9f..a713bde0 100644
--- a/create-rust-app_cli/src/plugins/dev.rs
+++ b/create-rust-app_cli/src/plugins/dev.rs
@@ -1,11 +1,11 @@
-use crate::utils::fs;
-use crate::utils::logger::add_file_msg;
+use crate::logger::register_service_msg;
 use crate::plugins::InstallConfig;
 use crate::plugins::Plugin;
+use crate::utils::fs;
+use crate::utils::logger::add_file_msg;
+use crate::BackendFramework;
 use anyhow::Result;
 use rust_embed::RustEmbed;
-use crate::BackendFramework;
-use crate::logger::register_service_msg;
 
 pub struct Dev {}
 
@@ -20,7 +20,9 @@ impl Plugin for Dev {
 
     fn install(&self, install_config: InstallConfig) -> Result<()> {
         for filename in Asset::iter() {
-            if filename.starts_with("README.md") || filename.contains(".cargo/admin") && !filename.contains(".cargo/admin/dist") {
+            if filename.starts_with("README.md")
+                || filename.contains(".cargo/admin") && !filename.contains(".cargo/admin/dist")
+            {
                 continue;
             }
 
@@ -58,25 +60,28 @@ const App = () => {"#,
             BackendFramework::ActixWeb => {
                 register_service_msg("(dev-only) /development");
                 register_service_msg("(dev-only) /admin");
-                fs::replace("backend/main.rs",
-                            r#"/* Development-only routes */"#,
-                            r#"/* Development-only routes */
+                fs::replace(
+                    "backend/main.rs",
+                    r#"/* Development-only routes */"#,
+                    r#"/* Development-only routes */
             // Mount development-only API routes
             api_scope = api_scope.service(create_rust_app::dev::endpoints(web::scope("/development")));
             // Mount the admin dashboard on /admin
-            app = app.service(web::scope("/admin").service(Files::new("/", ".cargo/admin/dist/").index_file("admin.html")));"#)?;
-
-            },
+            app = app.service(web::scope("/admin").service(Files::new("/", ".cargo/admin/dist/").index_file("admin.html")));"#,
+                )?;
+            }
             BackendFramework::Poem => {
                 register_service_msg("(dev-only) /development");
                 register_service_msg("(dev-only) /admin");
-                fs::replace("backend/main.rs",
-                            r#"/* Development-only routes */"#,
-                            r#"/* Development-only routes */
+                fs::replace(
+                    "backend/main.rs",
+                    r#"/* Development-only routes */"#,
+                    r#"/* Development-only routes */
         // Mount development-only API routes
         api_routes = api_routes.nest("/development", create_rust_app::dev::api());
         // Mount the admin dashboard on /admin
-        app = app.at("/admin", StaticFilesEndpoint::new(".cargo/admin/dist").index_file("admin.html"));"#)?;
+        app = app.at("/admin", StaticFilesEndpoint::new(".cargo/admin/dist").index_file("admin.html"));"#,
+                )?;
             }
         }
 
diff --git a/create-rust-app_cli/src/plugins/graphql.rs b/create-rust-app_cli/src/plugins/graphql.rs
index cfed9efa..c7330975 100644
--- a/create-rust-app_cli/src/plugins/graphql.rs
+++ b/create-rust-app_cli/src/plugins/graphql.rs
@@ -1,11 +1,11 @@
+use crate::content::cargo_toml::add_dependency;
+use crate::logger::register_service_msg;
 use crate::plugins::InstallConfig;
 use crate::plugins::Plugin;
 use crate::utils::logger::add_file_msg;
+use crate::{fs, BackendFramework};
 use anyhow::Result;
 use rust_embed::RustEmbed;
-use crate::{BackendFramework, fs};
-use crate::content::cargo_toml::add_dependency;
-use crate::logger::{register_service_msg};
 
 pub struct GraphQL {}
 
@@ -36,14 +36,30 @@ impl Plugin for GraphQL {
             std::fs::write(file_path, file_contents)?;
         }
 
-        add_dependency(&install_config.project_dir, "async-graphql", r#"async-graphql = "3.0.38""#)?;
-        add_dependency(&install_config.project_dir, "jsonwebtoken", r#"jsonwebtoken = "8.1.0""#)?;
+        add_dependency(
+            &install_config.project_dir,
+            "async-graphql",
+            r#"async-graphql = "3.0.38""#,
+        )?;
+        add_dependency(
+            &install_config.project_dir,
+            "jsonwebtoken",
+            r#"jsonwebtoken = "8.1.0""#,
+        )?;
         match install_config.backend_framework {
             BackendFramework::ActixWeb => {
-                add_dependency(&install_config.project_dir, "async-graphql-actix-web", r#"async-graphql-actix-web = "3.0.38""#)?;
-            },
+                add_dependency(
+                    &install_config.project_dir,
+                    "async-graphql-actix-web",
+                    r#"async-graphql-actix-web = "3.0.38""#,
+                )?;
+            }
             BackendFramework::Poem => {
-                add_dependency(&install_config.project_dir, "async-graphql-poem", r#"async-graphql-poem = "3.0.38""#)?;
+                add_dependency(
+                    &install_config.project_dir,
+                    "async-graphql-poem",
+                    r#"async-graphql-poem = "3.0.38""#,
+                )?;
             }
         }
 
@@ -53,7 +69,11 @@ impl Plugin for GraphQL {
 import { GraphQLPage } from './containers/GraphQLPage'"#,
         )?;
 
-        fs::replace("frontend/src/App.tsx", "/* CRA: app hooks */", "/* CRA: app hooks */\n  const apollo = useApolloClient()")?;
+        fs::replace(
+            "frontend/src/App.tsx",
+            "/* CRA: app hooks */",
+            "/* CRA: app hooks */\n  const apollo = useApolloClient()",
+        )?;
 
         fs::replace(
             "frontend/src/App.tsx",
@@ -62,7 +82,10 @@ import { GraphQLPage } from './containers/GraphQLPage'"#,
           <a className="NavButton" onClick={() => navigate('/gql')}>GraphQL</a>"#,
         )?;
 
-        fs::replace("frontend/bundles/index.tsx", "ReactDOM.createRoot", r##"import {ApolloProvider} from "@apollo/client";
+        fs::replace(
+            "frontend/bundles/index.tsx",
+            "ReactDOM.createRoot",
+            r##"import {ApolloProvider} from "@apollo/client";
 import {useAuthenticatedApolloClient} from "../src/hooks/useAuthenticatedApolloClient";
 
 const AuthenticatedApolloProvider = (props: { children: React.ReactNode }) => {
@@ -73,17 +96,24 @@ const AuthenticatedApolloProvider = (props: { children: React.ReactNode }) => {
     </ApolloProvider>
 }
 
-ReactDOM.createRoot"##)?;
+ReactDOM.createRoot"##,
+        )?;
 
-        fs::replace("frontend/src/App.tsx",
-                    r#"{/* CRA: routes */}"#,
-                    r#"{/* CRA: routes */}
-            <Route path="/gql" element={<GraphQLPage />} />"#)?;
+        fs::replace(
+            "frontend/src/App.tsx",
+            r#"{/* CRA: routes */}"#,
+            r#"{/* CRA: routes */}
+            <Route path="/gql" element={<GraphQLPage />} />"#,
+        )?;
 
-        fs::replace("frontend/package.json", r##""dependencies": {"##, r##""dependencies": {
+        fs::replace(
+            "frontend/package.json",
+            r##""dependencies": {"##,
+            r##""dependencies": {
     "@apollo/client": "^3.5.10",
     "graphql-ws": "^5.6.4",
-    "graphql": "^16.3.0","##)?;
+    "graphql": "^16.3.0","##,
+        )?;
 
         fs::replace("backend/main.rs", "mod mail;", "mod mail;\nmod graphql;")?;
 
@@ -93,100 +123,136 @@ ReactDOM.createRoot"##)?;
         fs::replace("frontend/src/App.tsx", old_logout_link, new_logout_link)?;
 
         // make sure auth plugin is wrapped on top
-        fs::replace("frontend/bundles/index.tsx", "<AuthProvider>", "<AuthProvider>\n        <AuthenticatedApolloProvider>")?;
-        fs::replace("frontend/bundles/index.tsx", "</AuthProvider>", "</AuthenticatedApolloProvider>\n      </AuthProvider>")?;
-
+        fs::replace(
+            "frontend/bundles/index.tsx",
+            "<AuthProvider>",
+            "<AuthProvider>\n        <AuthenticatedApolloProvider>",
+        )?;
+        fs::replace(
+            "frontend/bundles/index.tsx",
+            "</AuthProvider>",
+            "</AuthenticatedApolloProvider>\n      </AuthProvider>",
+        )?;
 
         match install_config.backend_framework {
             BackendFramework::ActixWeb => {
-                fs::replace("backend/main.rs", "extern crate diesel;", r##"extern crate diesel;
+                fs::replace(
+                    "backend/main.rs",
+                    "extern crate diesel;",
+                    r##"extern crate diesel;
 
-use actix_web::guard;"##)?;
+use actix_web::guard;"##,
+                )?;
 
-                fs::replace("backend/main.rs",
-                            "app = app.app_data(Data::new(app_data.mailer.clone()));",
-                            r#"app = app.app_data(Data::new(app_data.mailer.clone()));
-        app = app.app_data(Data::new(schema.clone()));"#)?;
+                fs::replace(
+                    "backend/main.rs",
+                    "app = app.app_data(Data::new(app_data.mailer.clone()));",
+                    r#"app = app.app_data(Data::new(app_data.mailer.clone()));
+        app = app.app_data(Data::new(schema.clone()));"#,
+                )?;
 
                 // GraphQL subscription endpoint
                 //
-                crate::content::service::register_actix("graphql-websocket",
+                crate::content::service::register_actix(
+                    "graphql-websocket",
                     r#"web::resource("/graphql/ws")
                 .guard(guard::Get())
                 .guard(guard::Header("upgrade", "websocket"))
-                .to(graphql::index_ws)"#
+                .to(graphql::index_ws)"#,
                 )?;
 
                 // GraphQL query endpoint
                 //
                 crate::content::service::register_actix(
                     "graphql",
-                    r#"web::resource("/graphql").guard(guard::Post()).to(graphql::index)"#
+                    r#"web::resource("/graphql").guard(guard::Post()).to(graphql::index)"#,
                 )?;
 
                 // GraphQL Schema building
                 //
                 let mut other_data = String::new();
-                if install_config.plugin_storage { other_data.push_str(r#"
-        .data(app_data.storage.clone())"#)}
-                fs::replace("backend/main.rs", "create_rust_app::setup();", &format!(r##"create_rust_app::setup();
+                if install_config.plugin_storage {
+                    other_data.push_str(
+                        r#"
+        .data(app_data.storage.clone())"#,
+                    )
+                }
+                fs::replace(
+                    "backend/main.rs",
+                    "create_rust_app::setup();",
+                    &format!(
+                        r##"create_rust_app::setup();
 
     let schema = async_graphql::Schema::build(graphql::QueryRoot, graphql::MutationRoot, graphql::SubscriptionRoot)
         .data(app_data.database.clone())
         .data(app_data.mailer.clone()){other_data}
         .finish();
-"##, other_data=other_data))?;
+"##,
+                        other_data = other_data
+                    ),
+                )?;
 
                 // GraphQL Playground endpoint
                 //
                 register_service_msg("graphql-playground");
 
-                fs::replace("backend/main.rs",
-                r#"/* Development-only routes */"#,
-                r#"/* Development-only routes */
+                fs::replace(
+                    "backend/main.rs",
+                    r#"/* Development-only routes */"#,
+                    r#"/* Development-only routes */
             // Mount the GraphQL playground on /graphql
-            app = app.route("/graphql", web::get().to(graphql::index_playground));"#)?;
-
-            },
+            app = app.route("/graphql", web::get().to(graphql::index_playground));"#,
+                )?;
+            }
             BackendFramework::Poem => {
                 // GraphQL Schema building
                 //
-                fs::replace("backend/main.rs", "create_rust_app::setup();", r##"create_rust_app::setup();
+                fs::replace(
+                    "backend/main.rs",
+                    "create_rust_app::setup();",
+                    r##"create_rust_app::setup();
 
     let schema = async_graphql::Schema::build(graphql::QueryRoot, graphql::MutationRoot, graphql::SubscriptionRoot)
         .data(data.database.clone())
         .data(data.mailer.clone())
         .data(data.storage.clone())
         .finish();
-"##)?;
+"##,
+                )?;
 
                 // GraphQL subscription + query endpoints
                 //
-                fs::replace("backend/main.rs", "let mut api_routes = Route::new();", r#"let mut api_routes = Route::new();
+                fs::replace(
+                    "backend/main.rs",
+                    "let mut api_routes = Route::new();",
+                    r#"let mut api_routes = Route::new();
 		api_routes = api_routes.at("/graphql/ws", poem::get(graphql::index_ws));
-        api_routes = api_routes.at("/graphql", poem::post(graphql::index));"#)?;
+        api_routes = api_routes.at("/graphql", poem::post(graphql::index));"#,
+                )?;
 
                 // GraphQL Playground endpoint
                 //
                 register_service_msg("graphql-playground");
 
-                fs::replace("backend/main.rs",
-                            r#"/* Development-only routes */"#,
-                            r#"/* Development-only routes */
+                fs::replace(
+                    "backend/main.rs",
+                    r#"/* Development-only routes */"#,
+                    r#"/* Development-only routes */
             // Mount the GraphQL playground on /graphql
-        app = app.at("/graphql", poem::get(graphql::playground));"#)?;
+        app = app.at("/graphql", poem::get(graphql::playground));"#,
+                )?;
 
                 // Adding Schema to exposed data
                 //
-                fs::replace("backend/main.rs",
-                            ".with(AddData::new(data.database))",
-                            ".with(AddData::new(data.database))
-                .with(AddData::new(schema))"
+                fs::replace(
+                    "backend/main.rs",
+                    ".with(AddData::new(data.database))",
+                    ".with(AddData::new(data.database))
+                .with(AddData::new(schema))",
                 )?;
-            },
+            }
         };
 
-
         Ok(())
     }
 }
diff --git a/create-rust-app_cli/src/plugins/mod.rs b/create-rust-app_cli/src/plugins/mod.rs
index d47a2901..f29298a1 100644
--- a/create-rust-app_cli/src/plugins/mod.rs
+++ b/create-rust-app_cli/src/plugins/mod.rs
@@ -1,23 +1,24 @@
-pub mod dev;
 pub mod auth;
 pub mod container;
-pub mod storage;
+pub mod dev;
 pub mod graphql;
+pub mod storage;
 
-use crate::utils::logger;
+use crate::{project, BackendFramework};
+use crate::{utils::logger, BackendDatabase};
 use anyhow::Result;
 use std::path::PathBuf;
-use crate::{BackendFramework, project};
 
 #[derive(Clone)]
 pub struct InstallConfig {
     pub project_dir: PathBuf,
     pub backend_framework: BackendFramework,
+    pub backend_database: BackendDatabase,
     pub plugin_dev: bool,
     pub plugin_auth: bool,
     pub plugin_container: bool,
     pub plugin_storage: bool,
-    pub plugin_graphql: bool
+    pub plugin_graphql: bool,
 }
 
 pub trait Plugin {
@@ -48,7 +49,10 @@ pub trait Plugin {
 
     fn after_install(&self, install_config: InstallConfig) -> Result<()> {
         // cleanup
-        project::remove_non_framework_files(&install_config.project_dir, install_config.backend_framework)?;
+        project::remove_non_framework_files(
+            &install_config.project_dir,
+            install_config.backend_framework,
+        )?;
 
         logger::command_msg("git add -A");
 
diff --git a/create-rust-app_cli/src/plugins/storage.rs b/create-rust-app_cli/src/plugins/storage.rs
index 41745a22..f31a2f68 100644
--- a/create-rust-app_cli/src/plugins/storage.rs
+++ b/create-rust-app_cli/src/plugins/storage.rs
@@ -2,10 +2,10 @@ use crate::plugins::InstallConfig;
 use crate::plugins::Plugin;
 use crate::utils::fs;
 use crate::utils::logger::add_file_msg;
+use crate::{BackendDatabase, BackendFramework};
 use anyhow::Result;
 use indoc::indoc;
 use rust_embed::RustEmbed;
-use crate::BackendFramework;
 
 pub struct Storage {}
 
@@ -36,35 +36,41 @@ impl Plugin for Storage {
         // ===============================
 
         fs::append(
-           ".env.example",
+            ".env.example",
             r#"
 S3_HOST=http://localhost:9000
 S3_REGION=minio
 S3_BUCKET=bucket
 S3_ACCESS_KEY_ID=access_key
 S3_SECRET_ACCESS_KEY=secret_key
-"#
+"#,
         )?;
 
-        fs::replace("frontend/src/App.tsx",
-        r#"{/* CRA: routes */}"#,
-        r#"{/* CRA: routes */}
-            <Route path="/files" element={<Files />} />"#)?;
+        fs::replace(
+            "frontend/src/App.tsx",
+            r#"{/* CRA: routes */}"#,
+            r#"{/* CRA: routes */}
+            <Route path="/files" element={<Files />} />"#,
+        )?;
 
-        fs::replace("frontend/src/App.tsx",
-        r#"<a className="NavButton" onClick={() => navigate('/todos')}>Todos</a>"#,
+        fs::replace(
+            "frontend/src/App.tsx",
+            r#"<a className="NavButton" onClick={() => navigate('/todos')}>Todos</a>"#,
             r#"<a className="NavButton" onClick={() => navigate('/todos')}>Todos</a>
-        <a className="NavButton" onClick={() => navigate('/files')}>Files</a>"#
+        <a className="NavButton" onClick={() => navigate('/files')}>Files</a>"#,
         )?;
 
-        fs::replace("frontend/src/App.tsx",
-        r##"import { Todos } from './containers/Todo'"##,
-        r##"import { Todos } from './containers/Todo'
-import { Files } from './containers/Files'"##)?;
+        fs::replace(
+            "frontend/src/App.tsx",
+            r##"import { Todos } from './containers/Todo'"##,
+            r##"import { Todos } from './containers/Todo'
+import { Files } from './containers/Files'"##,
+        )?;
 
         crate::content::migration::create(
             "plugin_storage",
-            indoc! {r#"
+            match install_config.backend_database {
+                BackendDatabase::Postgres => indoc! {r#"
 CREATE TABLE attachment_blobs(
   id SERIAL PRIMARY KEY,
 
@@ -89,6 +95,32 @@ CREATE TABLE attachments(
   created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
 );
 "#},
+                BackendDatabase::Sqlite => indoc! {r#"
+CREATE TABLE attachment_blobs(
+  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+
+  key TEXT NOT NULL,
+  file_name TEXT NOT NULL,
+  content_type TEXT,
+  byte_size BIGINT NOT NULL,
+  checksum TEXT NOT NULL,
+  service_name TEXT NOT NULL,
+
+  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE attachments(
+  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+
+  name TEXT NOT NULL,
+  record_type TEXT NOT NULL,
+  record_id INTEGER NOT NULL,
+  blob_id INTEGER REFERENCES attachment_blobs(id) NOT NULL,
+
+  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+"#}
+            },
             indoc! {r#"
 DROP TABLE attachments CASCADE ALL;
 DROP TABLE attachment_blobs CASCADE ALL;
@@ -97,31 +129,28 @@ DROP TABLE attachment_blobs CASCADE ALL;
 
         match install_config.backend_framework {
             BackendFramework::ActixWeb => {
-
                 crate::content::service::register_actix(
                     "file",
-                    r#"services::file::endpoints(web::scope("/files"))"#
+                    r#"services::file::endpoints(web::scope("/files"))"#,
                 )?;
 
-                fs::replace("backend/main.rs",
-                            "app = app.app_data(Data::new(app_data.mailer.clone()));",
-                            r#"app = app.app_data(Data::new(app_data.mailer.clone()));
-        app = app.app_data(Data::new(app_data.storage.clone()));"#)?;
-
-            },
-            BackendFramework::Poem => {
-                crate::content::service::register_poem(
-                    "file",
-                    "services::file::api()",
-                    "/files",
+                fs::replace(
+                    "backend/main.rs",
+                    "app = app.app_data(Data::new(app_data.mailer.clone()));",
+                    r#"app = app.app_data(Data::new(app_data.mailer.clone()));
+        app = app.app_data(Data::new(app_data.storage.clone()));"#,
                 )?;
+            }
+            BackendFramework::Poem => {
+                crate::content::service::register_poem("file", "services::file::api()", "/files")?;
 
-                fs::replace("backend/main.rs",
-                ".with(AddData::new(data.database))",
+                fs::replace(
+                    "backend/main.rs",
+                    ".with(AddData::new(data.database))",
                     ".with(AddData::new(data.database))
-                .with(AddData::new(data.storage))"
+                .with(AddData::new(data.storage))",
                 )?;
-            },
+            }
         };
 
         fs::append("backend/services/mod.rs", "pub mod file;")?;
diff --git a/create-rust-app_cli/src/qsync/processor.rs b/create-rust-app_cli/src/qsync/processor.rs
index df25a999..7c1a9cb5 100644
--- a/create-rust-app_cli/src/qsync/processor.rs
+++ b/create-rust-app_cli/src/qsync/processor.rs
@@ -275,14 +275,17 @@ fn extract_endpoint_information(
         .trim_end_matches("/");
 
     // the part extracted from the attribute, for example: `#[post("/{id}"]`
-    let handler_path = path.trim_matches('"').trim_start_matches('/').trim_end_matches("/");
-    let handler_path = if !handler_path.is_empty() { "/".to_string() + handler_path } else { "".to_string() };
+    let handler_path = path
+        .trim_matches('"')
+        .trim_start_matches('/')
+        .trim_end_matches("/");
+    let handler_path = if !handler_path.is_empty() {
+        "/".to_string() + handler_path
+    } else {
+        "".to_string()
+    };
 
-    hook.endpoint_url = format!(
-        "/api/{}{}",
-        endpoint_base,
-        handler_path
-    );
+    hook.endpoint_url = format!("/api/{}{}", endpoint_base, handler_path);
 
     hook.endpoint_verb = verb;
 }
diff --git a/create-rust-app_cli/src/utils/git.rs b/create-rust-app_cli/src/utils/git.rs
index e604a6fb..1a9a37b7 100644
--- a/create-rust-app_cli/src/utils/git.rs
+++ b/create-rust-app_cli/src/utils/git.rs
@@ -22,4 +22,4 @@ pub fn set_config(project_dir: &PathBuf, config_item: &str, config_value: &str)
         .status()
         .expect("failed to execute process")
         .success()
-}
\ No newline at end of file
+}
diff --git a/create-rust-app_cli/src/utils/logger.rs b/create-rust-app_cli/src/utils/logger.rs
index 4432cca1..0c740b0d 100644
--- a/create-rust-app_cli/src/utils/logger.rs
+++ b/create-rust-app_cli/src/utils/logger.rs
@@ -13,7 +13,10 @@ pub fn add_file_msg(file: &str) {
 }
 
 pub fn register_service_msg(service_name: &str) {
-    message(&format!("Registering service {}", style(service_name).yellow()));
+    message(&format!(
+        "Registering service {}",
+        style(service_name).yellow()
+    ));
 }
 
 pub fn modify_file_msg(file: &str) {
@@ -25,7 +28,11 @@ pub fn remove_file_msg(file: &str) {
 }
 
 pub fn rename_file_msg(src: &str, dest: &str) {
-    message(&format!("Renaming {} to {}", style(src).yellow(), style(dest).yellow()));
+    message(&format!(
+        "Renaming {} to {}",
+        style(src).yellow(),
+        style(dest).yellow()
+    ));
 }
 
 pub fn plugin_msg(name: &str) {
@@ -105,11 +112,10 @@ pub fn project_created_msg(project_dir: std::path::PathBuf) {
     }
 
     if !is_tsync_cli_installed {
-        message(&format!("• Install tsync (to generate typescript types from rust)"));
         message(&format!(
-            "  $ {}",
-            style("cargo install tsync").cyan()
+            "• Install tsync (to generate typescript types from rust)"
         ));
+        message(&format!("  $ {}", style("cargo install tsync").cyan()));
     }
 
     message(&format!("• Begin development!"));
diff --git a/create-rust-app_cli/src/utils/mod.rs b/create-rust-app_cli/src/utils/mod.rs
index de744a18..b872eb93 100644
--- a/create-rust-app_cli/src/utils/mod.rs
+++ b/create-rust-app_cli/src/utils/mod.rs
@@ -1,3 +1,3 @@
 pub mod fs;
-pub mod logger;
 pub mod git;
+pub mod logger;
diff --git a/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+actix_web b/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+actix_web
index 90b3ae52..d96c4125 100644
--- a/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+actix_web
+++ b/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+actix_web
@@ -24,7 +24,7 @@ async fn all(db: Data<Database>, storage: Data<Storage>) -> HttpResponse {
     let mut files = blobs.iter().enumerate().map(|b| FileInfo {
         id: files[b.0].id,
         key: b.1.clone().key,
-        name: b.1.clone().file_name.unwrap_or("".to_string()),
+        name: b.1.clone().file_name,
         url: None,
     }).collect::<Vec<FileInfo>>();
 
diff --git a/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+poem b/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+poem
index 1f9f9f2b..489b01d2 100644
--- a/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+poem
+++ b/create-rust-app_cli/template-plugin-storage/backend/services/file.rs+poem
@@ -25,7 +25,7 @@ async fn all(db: Data<&Database>, storage: Data<&Storage>) -> Result<impl IntoRe
     let mut files = blobs.iter().enumerate().map(|b| FileInfo {
         id: files[b.0].id,
         key: b.1.clone().key,
-        name: b.1.clone().file_name.unwrap_or("".to_string()),
+        name: b.1.clone().file_name,
         url: None,
     }).collect::<Vec<FileInfo>>();
 
diff --git a/create-rust-app_cli/template/backend/models/todo.rs b/create-rust-app_cli/template/backend/models/todo.rs+database_postgres
similarity index 98%
rename from create-rust-app_cli/template/backend/models/todo.rs
rename to create-rust-app_cli/template/backend/models/todo.rs+database_postgres
index 4d1575a5..e82be6ef 100644
--- a/create-rust-app_cli/template/backend/models/todo.rs
+++ b/create-rust-app_cli/template/backend/models/todo.rs+database_postgres
@@ -21,7 +21,7 @@ pub struct PaginationParams {
 }
 
 impl PaginationParams {
-    const MAX_PAGE_SIZE: u16 = 100;
+    pub const MAX_PAGE_SIZE: u16 = 100;
 }
 
 #[tsync::tsync]
diff --git a/create-rust-app_cli/template/backend/models/todo.rs+database_sqlite b/create-rust-app_cli/template/backend/models/todo.rs+database_sqlite
new file mode 100644
index 00000000..c5f50872
--- /dev/null
+++ b/create-rust-app_cli/template/backend/models/todo.rs+database_sqlite
@@ -0,0 +1,88 @@
+use crate::diesel::*;
+use crate::schema::*;
+
+use create_rust_app::Connection;
+use chrono::NaiveDateTime;
+use diesel::QueryResult;
+use serde::{Deserialize, Serialize};
+
+#[tsync::tsync]
+pub type ID = i32;
+
+#[tsync::tsync]
+pub type UTC = NaiveDateTime;
+
+#[tsync::tsync]
+#[derive(serde::Deserialize)]
+pub struct PaginationParams {
+    pub page: i64,
+    pub page_size: i64,
+}
+
+impl PaginationParams {
+    pub const MAX_PAGE_SIZE: u16 = 100;
+}
+
+#[tsync::tsync]
+#[derive(
+Debug,
+Serialize,
+Deserialize,
+Clone,
+Queryable,
+Insertable,
+Identifiable,
+AsChangeset,
+)]
+#[diesel(table_name=todos)]
+pub struct Todo {
+    pub id: ID,
+    pub text: String,
+    pub created_at: UTC,
+}
+
+#[tsync::tsync]
+#[derive(Debug, Serialize, Deserialize, Clone, Insertable, AsChangeset)]
+#[diesel(table_name=todos)]
+pub struct TodoChangeset {
+    pub text: String,
+}
+
+pub fn create(db: &mut Connection, item: &TodoChangeset) -> QueryResult<Todo> {
+    use crate::schema::todos::dsl::*;
+
+    insert_into(todos).values(item).get_result::<Todo>(db)
+}
+
+pub fn read(db: &mut Connection, item_id: ID) -> QueryResult<Todo> {
+    use crate::schema::todos::dsl::*;
+
+    todos.filter(id.eq(item_id)).first::<Todo>(db)
+}
+
+pub fn read_all(db: &mut Connection, pagination: &PaginationParams) -> QueryResult<Vec<Todo>> {
+    use crate::schema::todos::dsl::*;
+
+    todos
+        .order(created_at)
+        .limit(pagination.page_size)
+        .offset(
+            pagination.page
+                * std::cmp::max(pagination.page_size, PaginationParams::MAX_PAGE_SIZE as i64),
+        )
+        .load::<Todo>(db)
+}
+
+pub fn update(db: &mut Connection, item_id: ID, item: &TodoChangeset) -> QueryResult<Todo> {
+    use crate::schema::todos::dsl::*;
+
+    diesel::update(todos.filter(id.eq(item_id)))
+        .set(item)
+        .get_result(db)
+}
+
+pub fn delete(db: &mut Connection, item_id: ID) -> QueryResult<usize> {
+    use crate::schema::todos::dsl::*;
+
+    diesel::delete(todos.filter(id.eq(item_id))).execute(db)
+}
diff --git a/create-rust-app_cli/template/backend/services/todo.rs+actix_web b/create-rust-app_cli/template/backend/services/todo.rs+actix_web
index d7ff02ba..1ebafbc2 100644
--- a/create-rust-app_cli/template/backend/services/todo.rs+actix_web
+++ b/create-rust-app_cli/template/backend/services/todo.rs+actix_web
@@ -1,49 +1,15 @@
-use crate::diesel::*;
-use crate::schema::*;
+use actix_web::{delete, Error, get, HttpResponse, post, put, Result, web::{Data, Json, Path, Query}};
 use create_rust_app::Database;
-
-use chrono::{DateTime, Utc};
-use actix_web::{Result, web::{Path, Json, Data, Query}, HttpResponse, delete, get, post, put, Error, Responder};
-use serde::{Deserialize, Serialize};
-
-#[tsync::tsync]
-#[derive(Debug, Serialize, Deserialize, Identifiable, AsChangeset, Clone, Queryable)]
-#[diesel(table_name=todos)]
-pub struct Todo {
-    pub id: i32,
-    pub text: String,
-    pub created_at: DateTime<Utc>,
-    pub updated_at: DateTime<Utc>,
-}
-
-#[tsync::tsync]
-#[derive(Debug, Insertable, Serialize, Deserialize, AsChangeset)]
-#[diesel(table_name=todos)]
-pub struct TodoJson {
-    pub text: String,
-}
-
-const MAX_PAGE_SIZE: u16 = 100;
-
-#[derive(Deserialize)]
-pub struct IndexRequest {
-    page: i64,
-    page_size: i64,
-}
+use crate::{models, models::todo::{Todo, TodoChangeset, PaginationParams}};
 
 #[get("")]
 async fn index(
     db: Data<Database>,
-    Query(info): Query<IndexRequest>,
+    Query(info): Query<PaginationParams>,
 ) -> HttpResponse {
     let mut db = db.pool.get().unwrap();
 
-    use crate::schema::todos::dsl::*;
-    let result = todos
-        .order(created_at)
-        .limit(10)
-        .offset(info.page * std::cmp::max(info.page_size, MAX_PAGE_SIZE as i64))
-        .load::<Todo>(&mut db);
+    let result = models::todo::read_all(&mut db, &info);
 
     if result.is_ok() {
         HttpResponse::Ok().json(result.unwrap())
@@ -59,8 +25,7 @@ async fn read(
 ) -> HttpResponse {
     let mut db = db.pool.get().unwrap();
 
-    use crate::schema::todos::dsl::*;
-    let result = todos.filter(id.eq(item_id.into_inner())).first::<Todo>(&mut db);
+    let result = models::todo::read(&mut db, item_id.into_inner());
 
     if result.is_ok() {
         HttpResponse::Ok().json(result.unwrap())
@@ -72,16 +37,11 @@ async fn read(
 #[post("")]
 async fn create(
     db: Data<Database>,
-    Json(item): Json<TodoJson>,
+    Json(item): Json<TodoChangeset>,
 ) -> Result<HttpResponse, Error> {
     let mut db = db.pool.get().unwrap();
 
-    use crate::schema::todos::dsl::*;
-
-    let result: Todo = insert_into(todos)
-        .values(&item)
-        .get_result::<Todo>(&mut db)
-        .expect("Creation error");
+    let result: Todo = models::todo::create(&mut db, &item).expect("Creation error");
 
     Ok(HttpResponse::Created().json(result))
 }
@@ -90,17 +50,11 @@ async fn create(
 async fn update(
     db: Data<Database>,
     item_id: Path<i32>,
-    Json(item): Json<TodoJson>,
+    Json(item): Json<TodoChangeset>,
 ) -> HttpResponse {
     let mut db = db.pool.get().unwrap();
 
-    use crate::schema::todos::dsl::*;
-
-    let result = diesel::update(todos.filter(id.eq(item_id.into_inner())))
-        .set(&TodoJson {
-            ..item
-        })
-        .execute(&mut db);
+    let result = models::todo::update(&mut db, item_id.into_inner(), &item);
 
     if result.is_ok() {
         HttpResponse::Ok().finish()
@@ -116,9 +70,7 @@ async fn destroy(
 ) -> HttpResponse {
     let mut db = db.pool.get().unwrap();
 
-    use crate::schema::todos::dsl::*;
-
-    let result = diesel::delete(todos.filter(id.eq(item_id.into_inner()))).execute(&mut db);
+    let result = models::todo::delete(&mut db, item_id.into_inner());
 
     if result.is_ok() {
         HttpResponse::Ok().finish()
diff --git a/create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/down.sql b/create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/down.sql+database_postgres
similarity index 100%
rename from create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/down.sql
rename to create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/down.sql+database_postgres
diff --git a/create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/up.sql b/create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/up.sql+database_postgres
similarity index 100%
rename from create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/up.sql
rename to create-rust-app_cli/template/migrations/00000000000000_diesel_initial_setup/up.sql+database_postgres
diff --git a/create-rust-app_cli/template/migrations/00000000000001_utc/down.sql b/create-rust-app_cli/template/migrations/00000000000001_utc/down.sql+database_postgres
similarity index 100%
rename from create-rust-app_cli/template/migrations/00000000000001_utc/down.sql
rename to create-rust-app_cli/template/migrations/00000000000001_utc/down.sql+database_postgres
diff --git a/create-rust-app_cli/template/migrations/00000000000001_utc/up.sql b/create-rust-app_cli/template/migrations/00000000000001_utc/up.sql+database_postgres
similarity index 100%
rename from create-rust-app_cli/template/migrations/00000000000001_utc/up.sql
rename to create-rust-app_cli/template/migrations/00000000000001_utc/up.sql+database_postgres
diff --git a/create-rust-app_cli/template/migrations/00000000000002_todos/down.sql b/create-rust-app_cli/template/migrations/00000000000002_todos/down.sql+database_postgres
similarity index 100%
rename from create-rust-app_cli/template/migrations/00000000000002_todos/down.sql
rename to create-rust-app_cli/template/migrations/00000000000002_todos/down.sql+database_postgres
diff --git a/create-rust-app_cli/template/migrations/00000000000002_todos/down.sql+database_sqlite b/create-rust-app_cli/template/migrations/00000000000002_todos/down.sql+database_sqlite
new file mode 100644
index 00000000..08d761c7
--- /dev/null
+++ b/create-rust-app_cli/template/migrations/00000000000002_todos/down.sql+database_sqlite
@@ -0,0 +1,1 @@
+DROP TABLE todos CASCADE ALL;
\ No newline at end of file
diff --git a/create-rust-app_cli/template/migrations/00000000000002_todos/up.sql b/create-rust-app_cli/template/migrations/00000000000002_todos/up.sql+database_postgres
similarity index 100%
rename from create-rust-app_cli/template/migrations/00000000000002_todos/up.sql
rename to create-rust-app_cli/template/migrations/00000000000002_todos/up.sql+database_postgres
diff --git a/create-rust-app_cli/template/migrations/00000000000002_todos/up.sql+database_sqlite b/create-rust-app_cli/template/migrations/00000000000002_todos/up.sql+database_sqlite
new file mode 100644
index 00000000..adc3a05e
--- /dev/null
+++ b/create-rust-app_cli/template/migrations/00000000000002_todos/up.sql+database_sqlite
@@ -0,0 +1,5 @@
+CREATE TABLE todos (
+  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+  text TEXT NOT NULL,
+  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);


Test patch: