{"id":11825,"date":"2025-09-13T20:50:51","date_gmt":"2025-09-13T20:50:51","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=11825"},"modified":"2025-09-13T20:50:51","modified_gmt":"2025-09-13T20:50:51","slug":"trying-out-surrealdb-with-rust","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/trying-out-surrealdb-with-rust\/","title":{"rendered":"Trying out SurrealDB with Rust"},"content":{"rendered":"<p>SurrealDB is a multi-model database, which essentially means it allows storage of relation, document, graph, time-series, vector and search as well as geospatial models (as taken from the <a href=\"https:\/\/surrealdb.com\/docs\/surrealdb\" target=\"_blank\">SurrealDB Overview<\/a>).<\/p>\n<p>SurrealDB allows queries through an SQL like query language as well as GraphQL, HTTP and RPC.<\/p>\n<p>There are SDKs for Rust (which I&#8217;m going to use here) along with JavaScript, Java, Go, Python, .NET and PHP. <\/p>\n<p>Whilst you can install on Windows, Linux and Mac I prefer using Docker, so let&#8217;s run up an instance of SurrealDB <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker run --rm -p 8000:8000 surrealdb\/surrealdb:latest start --log trace --user root --pass root memory\r\n<\/pre>\n<p>With a volume, either create yourself a folder (i.e. mkdir mydata) or use an existing path<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker run --rm -p 8000:8000 surrealdb\/surrealdb:latest start --log trace --user root --pass root mydb:\/mydata\/mydatabase.db\r\n<\/pre>\n<p>If you&#8217;d like to run a web based UI for SurrealDB, you can run Surrealist<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndocker run -d -p 8080:8080 surrealdb\/surrealist:latest\r\n<\/pre>\n<p>Then use this to connect to your running instance, default user is admin, default password is admin (obviously change this in a real world usage).<\/p>\n<p>Once connected via Surrealist we can create a namespace and database, here&#8217;s a simple example of such a query run via Surrealist<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nUSE NS myns DB mydb;\r\n<\/pre>\n<p>Yes, we literally just use the namespace and database for the first time to create both. Now let&#8217;s a some data, creating a &#8220;table&#8221; using<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nCREATE person CONTENT {\r\n  first_name: &quot;Scooby&quot;,\r\n  last_name: &quot;Doo&quot;,\r\n  age: 42,\r\n  email: &quot;scooby.doo@example.com&quot;\r\n};\r\n<\/pre>\n<p>We can query for the list of &#8220;person&#8221; rows using<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nSELECT * FROM person;\r\n<\/pre>\n<p>As you can see, it&#8217;s very SQL like syntax with some differences. <\/p>\n<p>We didn&#8217;t created an id or such like field, but if you select the rows from the person table you&#8217;ve notice something like this<\/p>\n<pre class=\"brush: plain; highlight: [6]; title: ; notranslate\" title=\"\">\r\n&#x5B;\r\n  {\r\n    age: 42,\r\n    email: &#039;scooby.doo@example.com&#039;,\r\n    first_name: &#039;Scooby&#039;,\r\n    id: person:77xrs2c05oe9bmtgjbhq,\r\n    last_ame: &#039;Doo&#039;\r\n  }\r\n]\r\n<\/pre>\n<p>We could have supplied an id ourselves like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nCREATE person CONTENT {\r\n  first_name: &quot;Fred&quot;,\r\n  last_name: &quot;Jones&quot;,\r\n  age: 19,\r\n  id: person:fredjones,\r\n  email: &quot;fred.jones@example.com&quot;\r\n};\r\n<\/pre>\n<p>We can update a row using <\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nUPDATE person:77xrs2c05oe9bmtgjbhq SET name=&quot;Scrappy&quot;, age = 23;\r\n<\/pre>\n<p>There are obviously more commands\/queries we could use, but let&#8217;s move on to using the DB from Rust. <\/p>\n<p>We&#8217;ll start by adding a few dependencies to Cargo.toml<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;dependencies]\r\ntokio = { version = &quot;1.47.1&quot;, features = &#x5B;&quot;full&quot;] }\r\nsurrealdb = &quot;2.3.8&quot;\r\nserde = { version = &quot;1.0.219&quot;, features = &#x5B;&quot;derive&quot;] }\r\n<\/pre>\n<p>Next update main.rs to look like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuse surrealdb::{Surreal};\r\nuse surrealdb::engine::remote::ws::Ws;\r\nuse std::error::Error;\r\nuse surrealdb::opt::auth::Root;\r\n\r\nuse surrealdb::sql::Thing;\r\nuse serde::Deserialize;\r\n\r\n#&#x5B;derive(Debug, Deserialize)]\r\nstruct Person {\r\n    id: Thing,\r\n    first_name: String,\r\n    last_name: String,\r\n    email: String,\r\n    age: u32,\r\n}\r\n\r\n#&#x5B;tokio::main]\r\nasync fn main() -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {\r\n    let db = Surreal::new::&lt;Ws&gt;(&quot;127.0.0.1:8000&quot;).await?;\r\n    db.signin(Root { username: &quot;root&quot;, password: &quot;root&quot; }).await?;\r\n    db.use_ns(&quot;myns&quot;).use_db(&quot;mydb&quot;).await?;\r\n\r\n    let result: Vec&lt;Person&gt; = db.query(&quot;SELECT * FROM person&quot;).await?.take(0)?;\r\n\r\n    println!(&quot;{:?}&quot;, result);\r\n    Ok(())\r\n}\r\n<\/pre>\n<p>We&#8217;re using the default username and password. Ofcourse you should change the password for this user and create your own user, but for now, let&#8217;s just get things up and running.<\/p>\n<p>Notice that we connect to SurrealDB via the web socket.<\/p>\n<p>You may have also noticed that in our Person struct we have an id <em>Thing<\/em>. This is essentially a record pointer, which has the table name and record id.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>SurrealDB is a multi-model database, which essentially means it allows storage of relation, document, graph, time-series, vector and search as well as geospatial models (as taken from the SurrealDB Overview). SurrealDB allows queries through an SQL like query language as well as GraphQL, HTTP and RPC. There are SDKs for Rust (which I&#8217;m going to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[191,755],"tags":[],"class_list":["post-11825","post","type-post","status-publish","format-standard","hentry","category-rust","category-surrealdb"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11825","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=11825"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11825\/revisions"}],"predecessor-version":[{"id":11837,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11825\/revisions\/11837"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=11825"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=11825"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=11825"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}