{"id":17494,"date":"2025-08-20T14:50:19","date_gmt":"2025-08-20T21:50:19","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=17494"},"modified":"2025-08-21T12:48:21","modified_gmt":"2025-08-21T19:48:21","slug":"rag-app-vector-ios","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/","title":{"rendered":"How I Built a Plant RAG Application with Couchbase Vector Search on iOS"},"content":{"rendered":"<p>You know that feeling when you see a beautiful plant at the store but have no idea what it is or how to care for it? That&#8217;s exactly what happened to me last spring, and it got me thinking &#8211; what if I could just point my phone at any plant and instantly know everything about it?<\/p>\n<p>So I built PlantPal, an iOS app that identifies plants from photos and provides AI-powered care advice. The cool part? Everything runs on-device using Couchbase vector search. No internet required, no photos sent to servers, just pure local plant identification magic.<\/p>\n<h2 style=\"font-weight: 400\">What I built<\/h2>\n<p>PlantPal turned out to be quite the technical adventure. It&#8217;s basically a RAG application that can identify plants from your camera and then chat with you about care instructions. But here&#8217;s what makes it different from other plant apps:<\/p>\n<p>The whole thing runs locally on your phone. Point your camera at a snake plant, and it&#8217;ll instantly know it&#8217;s a snake plant. Ask it &#8220;how often should I water this?&#8221;, and it&#8217;ll give you specific advice for that exact plant &#8211; all without sending a single byte to the cloud.<\/p>\n<p>Oh, and I managed to squeeze the entire app from a ridiculous 800MB down to just 14MB. More on that disaster later.<\/p>\n<h2 style=\"font-weight: 400\">Demo video<\/h2>\n<div style=\"width: 480px;\" class=\"wp-video\"><!--[if lt IE 9]><script>document.createElement('video');<\/script><![endif]-->\n<video class=\"wp-video-shortcode\" id=\"video-17494-1\" width=\"480\" height=\"840\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/plant-app-video-1.mp4?_=1\" \/><a href=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/plant-app-video-1.mp4\">https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/plant-app-video-1.mp4<\/a><\/video><\/div>\n<h2 style=\"font-weight: 400\">The tech stack (or: how I learned to love vector databases)<\/h2>\n<p>Building this thing required quite a few pieces:<\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><b>iOS + Swift<\/b> &#8211; Obviously, since I wanted it on my iPhone<\/li>\n<li><b>Couchbase Lite Vector Search<\/b> &#8211; This was the game-changer for local plant identification<\/li>\n<li><b>MobileCLIP<\/b> &#8211; Apple&#8217;s computer vision model for turning images into numbers<\/li>\n<li><b>Core ML<\/b> &#8211; For running everything locally<\/li>\n<li><b>Foundation Models<\/b> &#8211; <a href=\"https:\/\/developer.apple.com\/machine-learning\/foundation-models\/\" target=\"_blank\" rel=\"noopener\">Apple&#8217;s on-device AI framework<\/a> for chat functionality, providing privacy-first LLM capabilities without cloud dependencies<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>The whole philosophy was &#8220;<em>keep everything local<\/em>.&#8221; No cloud APIs, no sending plant photos to random servers, no privacy nightmares. Just you, your phone, and some very clever math.<\/p>\n<hr \/>\n<h2 style=\"font-weight: 400\">Part 1: Vector search &#8211; it&#8217;s not as scary as it sounds<\/h2>\n<h3 style=\"font-weight: 400\">Why most plant apps suck<\/h3>\n<p>Let&#8217;s be honest &#8211; most plant identification apps are pretty frustrating. You take a photo, wait 3-5 seconds while it uploads to some server, then get back a result that may or may not be accurate. Plus, you&#8217;re basically sending photos of your houseplants to who-knows-where.<\/p>\n<p>I wanted something that just worked instantly, like pointing your camera at a plant and immediately knowing what it is. No waiting, no internet required, no privacy concerns.<\/p>\n<p><b>Vector search.<\/b> I know, I know &#8211; it sounds super technical and intimidating. But it&#8217;s actually a pretty elegant solution once you wrap your head around it.<\/p>\n<h3 style=\"font-weight: 400\">The magic of vector embeddings<\/h3>\n<p>Here&#8217;s the crazy part: you can turn any image into a list of numbers. Not like pixel values, but actual meaningful numbers that represent what&#8217;s IN the image.<\/p>\n<pre class=\"\">Rose photo \u2192 [0.1, 0.8, 0.3, ...] (512 numbers)\r\nTulip photo \u2192 [0.9, 0.2, 0.1, ...] (512 numbers)\r\n<\/pre>\n<p>The beautiful thing is that similar plants end up with similar numbers. Two rose photos will have very similar vectors, while a rose and a cactus will be completely different.<\/p>\n<p>Once I had this insight, the solution became obvious &#8211; just compare the numbers! Couchbase Vector Search handles all the heavy lifting of finding similar vectors efficiently.<\/p>\n<p>The actual implementation turned out to be surprisingly clean:<\/p>\n<pre class=\"nums:false lang:swift decode:true\">func search(image: UIImage) -&gt; [Record] {\r\n\u00a0\u00a0\u00a0\u00a0\/\/ Turn the camera photo into numbers\r\n\u00a0\u00a0\u00a0\u00a0let embeddings = AI.shared.embeddings(for: image, attention: .zoom(factors: [1, 2]))\r\n\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0for embedding in embeddings {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let plantSearchResults = self.searchPlants(vector: embedding)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if !plantSearchResults.isEmpty {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return plantSearchResults\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0return []\r\n}\r\n<\/pre>\n<hr \/>\n<h2 style=\"font-weight: 400\">Part 2: the great MobileCLIP migration<\/h2>\n<h3 style=\"font-weight: 400\">When Vision Framework wasn&#8217;t enough<\/h3>\n<p>So here&#8217;s where things got interesting. I started with Apple&#8217;s Vision framework because, well, it&#8217;s built into iOS and seemed like the obvious choice. For my initial test with 47 plant photos, it worked perfectly fine. I was feeling pretty good about myself.<\/p>\n<p>Then I got ambitious. What if I could build a database with 15,000+ plant species? That&#8217;s when everything fell apart.<\/p>\n<p><strong>The problem was accuracy.<\/strong>\u00a0When I tested Vision embeddings on larger datasets, plants that looked similar kept getting confused with each other. Like, the app would think a Snake Plant was a ZZ Plant, which is&#8230; not great when you&#8217;re trying to give watering advice.<\/p>\n<p>Turns out Vision framework embeddings just weren&#8217;t distinct enough for my use case. The vectors for similar-looking plants were too close together, so the app couldn&#8217;t tell them apart reliably.<\/p>\n<h3 style=\"font-weight: 400\">MobileCLIP<\/h3>\n<p>After some digging around (and a lot of frustration), I discovered MobileCLIP. It&#8217;s specifically designed for image similarity tasks, and the difference was night and day. Suddenly, similar plants had much more distinct embeddings, and my accuracy went way up.<\/p>\n<p>The migration was a bit of work &#8211; I had to rewrite the embedding generation pipeline &#8211; but totally worth it. Now I could confidently scale to thousands of plant species without accuracy falling off a cliff.<\/p>\n<hr \/>\n<h2 style=\"font-weight: 400\">Part 3: The 800MB Disaster (and how I fixed it)<\/h2>\n<h3 style=\"font-weight: 400\">When your app becomes larger than most games<\/h3>\n<p>So remember when I mentioned the 800MB disaster? Yeah, about that&#8230;<\/p>\n<p>My first version was absolutely ridiculous. I was shipping the full plant database with high-resolution images, plus multiple MobileCLIP models (S0, S1, S2, BLT &#8211; because why choose, right?), plus all the text models I thought I might need someday. The app was basically the size of a AAA mobile game.<\/p>\n<p>Nobody&#8217;s going to download an 800MB plant identification app. I mean, would you?<\/p>\n<h3 style=\"font-weight: 400\">The pre-computation breakthrough<\/h3>\n<p>That&#8217;s when I had what I like to call my &#8220;duh&#8221; moment. Why was I generating embeddings for the same 47 plants every single time the app launched? That&#8217;s just&#8230; wasteful.<\/p>\n<p><b>What I was doing (badly):<\/b><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><strong>App Bundle:<\/strong> Plant images (10MB) + All the models (800MB) = 810MB<\/li>\n<li><strong>Every app launch:<\/strong> Generate embeddings for all reference plants<\/li>\n<li><strong>Result:<\/strong> Slow startup, ridiculous file size<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><b>What I should have been doing:<\/b><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><strong>Build time:<\/strong> Generate embeddings once from plant images<\/li>\n<li><strong>App Bundle:<\/strong> Pre-computed embeddings (500KB) + 1 Model (14MB) = 14MB<\/li>\n<li><strong>Runtime:<\/strong> Only generate embeddings for new camera photos<\/li>\n<li><strong>Result:<\/strong> Instant startup, normal-sized app<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Here&#8217;s the pre-computed embedding loader:<\/p>\n<pre class=\"nums:false lang:swift decode:true\">class BuildTimeEmbeddingLoader {\r\n\u00a0\u00a0\u00a0\u00a0private var preComputedEmbeddings: [String: PreComputedPlantEmbedding] = [:]\r\n\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0func loadPreComputedEmbeddings() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0guard let embeddingsURL = Bundle.main.url(forResource: \"plant_embeddings\", withExtension: \"json\"),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let data = try? Data(contentsOf: embeddingsURL),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let embeddings = try? JSONDecoder().decode([PreComputedPlantEmbedding].self, from: data) else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Load 47 plants \u00d7 512 dimensions = ~500KB total\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0for embedding in embeddings {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0preComputedEmbeddings[embedding.plantId] = embedding\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0print(\" Loaded \\(embeddings.count) plants!\")\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p><b>Benefits:<\/b><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><b>Instant app startup:<\/b>\u00a0No embedding generation needed<\/li>\n<li><b>98% smaller storage:<\/b>\u00a0Embeddings vs images<\/li>\n<li><b>Better battery life:<\/b>\u00a0Less computation at runtime<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<h2 style=\"font-weight: 400\">Part 4: making Couchbase do the heavy lifting<\/h2>\n<h3 style=\"font-weight: 400\">Database setup (easier than I expected)<\/h3>\n<p>I&#8217;ll be honest &#8211; when I first heard &#8220;vector database,&#8221; I thought it would be this massive, complicated thing. But Couchbase Lite made it surprisingly straightforward:<\/p>\n<pre class=\"nums:false lang:swift decode:true\">\/\/ Enable vector search extension\r\ntry! CouchbaseLiteSwift.Extension.enableVectorSearch()\r\n\r\n\/\/ Create local database\r\nlet database = try! CouchbaseLiteSwift.Database(name: \"plantpal\")\r\nlet collection = try! database.defaultCollection()\r\n\r\n\/\/ Vector index for 512-dimensional plant embeddings (MobileCLIP S1 model output size)\r\n\/\/ VectorIndexConfiguration defines index parameters: data expression, vector dimensions, clustering centroids, and distance metrics\r\nvar imageVectorIndex = VectorIndexConfiguration(expression: \"image\", dimensions: 512, centroids: 8)\r\nimageVectorIndex.metric = .cosine\r\nimageVectorIndex.isLazy = true\r\n\r\ntry! collection.createIndex(withName: \"ImageVectorIndex\", config: imageVectorIndex)\r\n\r\n\/\/ Full-text search for plant names\r\nlet ftsIndex = FullTextIndexConfiguration([\"name\", \"scientificName\"])\r\ntry! collection.createIndex(withName: \"PlantNameIndex\", config: ftsIndex)\r\n\r\nprint(\" Vector search database ready!\")<\/pre>\n<h3 style=\"font-weight: 400\">The SQL++ that changed everything<\/h3>\n<p>Here&#8217;s where Couchbase really shines. Instead of writing complex similarity algorithms, I can just use SQL++ with a special vector function. It&#8217;s almost too easy:<\/p>\n<pre class=\"nums:false lang:swift decode:true\">private func searchPlants(vector: [Float]) -&gt; [Record] {\r\n\u00a0\u00a0\u00a0\u00a0let sql = \"\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0SELECT type, name, scientificName, price, location,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0wateringSchedule, careInstructions, characteristics,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0APPROX_VECTOR_DISTANCE(image, $embedding) AS distance\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FROM _\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0WHERE type = \"plant\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0AND distance BETWEEN 0 AND 0.4\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ORDER BY distance, name\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0LIMIT 1\r\n\u00a0\u00a0\u00a0\u00a0\"\"\"\r\n\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0let query = try collection.database.createQuery(sql)\r\n\u00a0\u00a0\u00a0\u00a0query.parameters = Parameters()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.setArray(MutableArrayObject(data: vector), forName: \"embedding\")\r\n\r\n\u00a0\u00a0\u00a0\u00a0\/\/ Process results into Plant objects\r\n\u00a0\u00a0\u00a0\u00a0var records = [Record]()\r\n\u00a0\u00a0\u00a0\u00a0for result in try query.execute() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let plant = Plant(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name: result[\"name\"].string ?? \"\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0scientificName: result[\"scientificName\"].string,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0wateringSchedule: extractWateringSchedule(from: result),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0careInstructions: extractCareInstructions(from: result),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0characteristics: extractCharacteristics(from: result)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0records.append(plant)\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0return records\r\n}<\/pre>\n<p><b>The `<\/b><a href=\"https:\/\/docs.couchbase.com\/couchbase-lite\/current\/csharp\/working-with-vector-search.html#vector-search-sql-support\" target=\"_blank\" rel=\"noopener\"><b>APPROX_VECTOR_DISTANCE<\/b><\/a><b>` function calculates approximate distance between a target vector and vectors in the database, enabling efficient hybrid search with SQL++ queries and support for multiple distance metrics.<\/b><\/p>\n<hr \/>\n<h2 style=\"font-weight: 400\">Part 5: teaching the AI about plants<\/h2>\n<h3 style=\"font-weight: 400\">Making chat actually useful<\/h3>\n<p>Okay, so I could identify plants. Cool. But then what? I wanted users to be able to ask questions like &#8220;how often should I water this?&#8221; and get actually helpful answers, not generic plant care advice.<\/p>\n<p>This is where RAG (Retrieval-Augmented Generation) comes in. Basically, I needed to give the AI specific context about whichever plant was just identified. Here&#8217;s how I structured all that plant knowledge:<\/p>\n<pre class=\"lang:swift decode:true\">class Plant: Record {\r\n\u00a0\u00a0\u00a0\u00a0let name: String?\r\n\u00a0\u00a0\u00a0\u00a0let scientificName: String?\r\n\u00a0\u00a0\u00a0\u00a0let wateringSchedule: WateringSchedule?\r\n\u00a0\u00a0\u00a0\u00a0let careInstructions: CareInstructions?\r\n\u00a0\u00a0\u00a0\u00a0let characteristics: PlantCharacteristics?\r\n\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0struct WateringSchedule {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let frequency: String\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let amount: String\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let notes: String\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\r\n\u00a0\u00a0\u00a0\u00a0struct CareInstructions {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let light: String\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let temperature: String\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let humidity: String\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let fertilizer: String\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let pruning: String\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\r\n\u00a0\u00a0\u00a0\u00a0struct PlantCharacteristics {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let toxicToPets: Bool\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let airPurifying: Bool\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let flowering: Bool\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0let difficulty: String\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p>When a plant is identified, I build rich context for the AI from local data:<\/p>\n<pre class=\"nums:false lang:swift decode:true\">private func buildPlantContext(for plant: Plant) -&gt; String {\r\n\u00a0\u00a0\u00a0\u00a0let context = \"\"\"\r\n\u00a0\u00a0\u00a0\u00a0You are PlantPal, an expert plant care assistant. You can ONLY answer questions about: \\(plant.name ?? \"Unknown Plant\").\r\n\r\n\u00a0\u00a0\u00a0\u00a0PLANT INFORMATION:\r\n\u00a0\u00a0\u00a0\u00a0Name: \\(plant.name ?? \"Unknown\")\r\n\u00a0\u00a0\u00a0\u00a0Scientific Name: \\(plant.scientificName ?? \"Not available\")\r\n\r\n\u00a0\u00a0\u00a0\u00a0WATERING SCHEDULE:\r\n\u00a0\u00a0\u00a0\u00a0\\(plant.wateringSchedule?.frequency ?? \"Not specified\")\r\n\u00a0\u00a0\u00a0\u00a0\\(plant.wateringSchedule?.notes ?? \"\")\r\n\r\n\u00a0\u00a0\u00a0\u00a0CARE INSTRUCTIONS:\r\n\u00a0\u00a0\u00a0\u00a0Light: \\(plant.careInstructions?.light ?? \"Not specified\")\r\n\u00a0\u00a0\u00a0\u00a0Temperature: \\(plant.careInstructions?.temperature ?? \"Not specified\")\r\n\u00a0\u00a0\u00a0\u00a0Humidity: \\(plant.careInstructions?.humidity ?? \"Not specified\")\r\n\r\n\u00a0\u00a0\u00a0\u00a0CHARACTERISTICS:\r\n\u00a0\u00a0\u00a0\u00a0Pet Safe: \\(plant.characteristics?.toxicToPets == false ? \"Yes\" : \"No\")\r\n\u00a0\u00a0\u00a0\u00a0Air Purifying: \\(plant.characteristics?.airPurifying == true ? \"Yes\" : \"No\")\r\n\u00a0\u00a0\u00a0\u00a0Difficulty: \\(plant.characteristics?.difficulty ?? \"Not specified\")\r\n\u00a0\u00a0\u00a0\u00a0\"\"\"\r\n\r\n\u00a0\u00a0\u00a0\u00a0return context\r\n}<\/pre>\n<p>This provides rich, contextual AI responses using the identified plant&#8217;s specific care information.<\/p>\n<h3 style=\"font-weight: 400\">Foundation models integration<\/h3>\n<p>The chat functionality leverages <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/\" target=\"_blank\" rel=\"noopener\">Apple&#8217;s Foundation Models<\/a> for on-device natural language processing, ensuring all conversations stay private while providing intelligent plant care guidance through context-aware responses.<\/p>\n<hr \/>\n<h2 style=\"font-weight: 400\">Part 6: performance optimizations<\/h2>\n<h3 style=\"font-weight: 400\">Size reduction journey<\/h3>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><b>Started with:<\/b> 8 MobileCLIP models (800MB)<\/li>\n<li><b>Optimized to:<\/b> 1 MobileCLIP-S1 model (120MB)<\/li>\n<li><b>Result:<\/b> 85% size reduction with better accuracy!<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2 style=\"font-weight: 400\">Part 7: what I learned (the hard way)<\/h2>\n<h3 style=\"font-weight: 400\">Things that actually worked<\/h3>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><b>Pre-computed embeddings<\/b> &#8211; This was probably my biggest win. Going from generating embeddings every startup to pre-computing them saved both startup time and 98% of the app size.<\/li>\n<li><b>MobileCLIP<\/b> &#8211; Way better than Vision framework for distinguishing between similar plants. Totally worth the migration headache.<\/li>\n<li><b>Couchbase Vector Search<\/b> &#8211; Having SQL for vector operations is a game-changer. No more writing custom similarity algorithms.<\/li>\n<li><b>Keeping everything local<\/b> &#8211; Users love not having to worry about internet connectivity or privacy.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2 style=\"font-weight: 400\">Things that didn&#8217;t go smoothly<\/h2>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><b>Model size optimization<\/b> &#8211; I went through way too many iterations trying to find the right balance between accuracy and file size. Shipping 8 different models was&#8230; not smart.<\/li>\n<li><b>Similarity thresholds<\/b> &#8211; Took forever to tune these properly. Too strict and nothing matches, too loose and everything matches.<\/li>\n<li><b>Build automation<\/b> &#8211; Setting up the embedding generation pipeline to run during builds was trickier than expected.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3 style=\"font-weight: 400\">If I were starting over<\/h3>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><b>Think about app size from day one<\/b> &#8211; Don&#8217;t ship 800MB apps, people won&#8217;t download them<\/li>\n<li><b>Test your embedding model at scale<\/b> &#8211; What works for 50 plants might not work for 5000<\/li>\n<li><b>Couchbase Vector Search is your friend<\/b> &#8211; Don&#8217;t reinvent vector similarity matching<\/li>\n<li><b>Build time optimization &gt; runtime optimization<\/b> &#8211; Do the heavy lifting during builds, not when users are waiting<\/li>\n<li><b>Real data reveals everything<\/b> &#8211; Your algorithm might work perfectly on curated test images and completely fail on actual user photos<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2 style=\"font-weight: 400\">What&#8217;s next?<\/h2>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Expanding to more plant species<\/li>\n<li>Adding plant care reminders and progress tracking<\/li>\n<li>Community features for plant sharing<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<h2 style=\"font-weight: 400\">Wrapping up<\/h2>\n<p>Building PlantPal turned out to be way more educational than I expected. I went in thinking &#8220;how hard could plant identification be?&#8221; and came out with a deep appreciation for vector databases, embedding models, and the art of mobile optimization.<\/p>\n<p>The coolest part? I can now point my phone at literally any plant and instantly know what it is and how to care for it. No internet required, no privacy concerns, just pure local magic.<\/p>\n<p><b>What I&#8217;m most proud of:<\/b><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li>Going from an 800MB monstrosity to a sleek 14MB app<\/li>\n<li>Achieving instant responses with smart pre-computation<\/li>\n<li>Building something that actually works reliably in the real world<\/li>\n<li>Proving that complex AI doesn&#8217;t need cloud servers<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Vector search turned out to be this perfect sweet spot between simplicity and power. Couchbase made the whole thing way easier than I thought it would be &#8211; being able to use SQL for vector operations feels almost like cheating.<\/p>\n<p>If you&#8217;re thinking about building something similar, just start small and iterate. My first version was terrible, but each iteration taught me something new. And definitely don&#8217;t ship an 800MB app on your first try. Trust me on this one.<\/p>\n<hr \/>\n<p><i>Have you built anything with vector search? I&#8217;d love to hear about it! And if you try building your own plant identification app, hit me up &#8211; I&#8217;m always curious to see what other people come up with.<\/i><\/p>\n<p><b>Resources:<\/b><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li><a href=\"https:\/\/github.com\/midopooler\/PlantPal\" target=\"_blank\" rel=\"noopener\">PlantPal Source Code<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/couchbase-lite\/current\/c\/vector-search.html\" target=\"_blank\" rel=\"noopener\">Couchbase Vector Search Docs<\/a><\/li>\n<li><a href=\"https:\/\/machinelearning.apple.com\/research\/mobileclip\" target=\"_blank\" rel=\"noopener\">MobileCLIP Paper<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/downloads\/?family=couchbase-lite\">Download Couchbase Lite<\/a><\/li>\n<li><a class=\"c-link\" href=\"https:\/\/www.couchbase.com\/products\/mobile\/\" target=\"_blank\" rel=\"noopener noreferrer\" data-stringify-link=\"https:\/\/www.couchbase.com\/products\/mobile\/\" data-sk=\"tooltip_parent\">Learn more about Couchbase Mobile<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>You know that feeling when you see a beautiful plant at the store but have no idea what it is or how to care for it? That&#8217;s exactly what happened to me last spring, and it got me thinking &#8211; [&hellip;]<\/p>\n","protected":false},"author":85668,"featured_media":17496,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[10122,1815,1810,9409,9937],"tags":[10149],"ppma_author":[10150],"class_list":["post-17494","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-artificial-intelligence-ai","category-best-practices-and-tutorials","category-couchbase-mobile","category-swift","category-vector-search","tag-coreml"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How I Built a Plant RAG Application with Couchbase Vector Search on iOS - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"Everything runs on-device using Couchbase vector search. No internet required, no photos sent to servers, just pure local plant identification magic.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How I Built a Plant RAG Application with Couchbase Vector Search on iOS\" \/>\n<meta property=\"og:description\" content=\"Everything runs on-device using Couchbase vector search. No internet required, no photos sent to servers, just pure local plant identification magic.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-20T21:50:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-08-21T19:48:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2400\" \/>\n\t<meta property=\"og:image:height\" content=\"1256\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Pulkit Midha - Developer Evangelist\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Pulkit Midha - Developer Evangelist\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/\"},\"author\":{\"name\":\"Pulkit Midha - Developer Evangelist\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/a5479b7c0b1e18e90b26eb1c23614247\"},\"headline\":\"How I Built a Plant RAG Application with Couchbase Vector Search on iOS\",\"datePublished\":\"2025-08-20T21:50:19+00:00\",\"dateModified\":\"2025-08-21T19:48:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/\"},\"wordCount\":1819,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png\",\"keywords\":[\"coreml\"],\"articleSection\":[\"Artificial Intelligence (AI)\",\"Best Practices and Tutorials\",\"Couchbase Mobile\",\"Swift\",\"Vector Search\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/\",\"name\":\"How I Built a Plant RAG Application with Couchbase Vector Search on iOS - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png\",\"datePublished\":\"2025-08-20T21:50:19+00:00\",\"dateModified\":\"2025-08-21T19:48:21+00:00\",\"description\":\"Everything runs on-device using Couchbase vector search. No internet required, no photos sent to servers, just pure local plant identification magic.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png\",\"width\":2400,\"height\":1256},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How I Built a Plant RAG Application with Couchbase Vector Search on iOS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/a5479b7c0b1e18e90b26eb1c23614247\",\"name\":\"Pulkit Midha - Developer Evangelist\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/55878bb5199f5fed15902ca3d02d7db8\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/pulkit-midha-couchbase.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/pulkit-midha-couchbase.png\",\"caption\":\"Pulkit Midha - Developer Evangelist\"},\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/pulkitmidha\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How I Built a Plant RAG Application with Couchbase Vector Search on iOS - The Couchbase Blog","description":"Everything runs on-device using Couchbase vector search. No internet required, no photos sent to servers, just pure local plant identification magic.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/","og_locale":"en_US","og_type":"article","og_title":"How I Built a Plant RAG Application with Couchbase Vector Search on iOS","og_description":"Everything runs on-device using Couchbase vector search. No internet required, no photos sent to servers, just pure local plant identification magic.","og_url":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/","og_site_name":"The Couchbase Blog","article_published_time":"2025-08-20T21:50:19+00:00","article_modified_time":"2025-08-21T19:48:21+00:00","og_image":[{"width":2400,"height":1256,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png","type":"image\/png"}],"author":"Pulkit Midha - Developer Evangelist","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Pulkit Midha - Developer Evangelist","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/"},"author":{"name":"Pulkit Midha - Developer Evangelist","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/a5479b7c0b1e18e90b26eb1c23614247"},"headline":"How I Built a Plant RAG Application with Couchbase Vector Search on iOS","datePublished":"2025-08-20T21:50:19+00:00","dateModified":"2025-08-21T19:48:21+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/"},"wordCount":1819,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png","keywords":["coreml"],"articleSection":["Artificial Intelligence (AI)","Best Practices and Tutorials","Couchbase Mobile","Swift","Vector Search"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/","url":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/","name":"How I Built a Plant RAG Application with Couchbase Vector Search on iOS - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png","datePublished":"2025-08-20T21:50:19+00:00","dateModified":"2025-08-21T19:48:21+00:00","description":"Everything runs on-device using Couchbase vector search. No internet required, no photos sent to servers, just pure local plant identification magic.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/blog-plant-rag-app.png","width":2400,"height":1256},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/rag-app-vector-ios\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How I Built a Plant RAG Application with Couchbase Vector Search on iOS"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/a5479b7c0b1e18e90b26eb1c23614247","name":"Pulkit Midha - Developer Evangelist","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/55878bb5199f5fed15902ca3d02d7db8","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/pulkit-midha-couchbase.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/pulkit-midha-couchbase.png","caption":"Pulkit Midha - Developer Evangelist"},"url":"https:\/\/www.couchbase.com\/blog\/author\/pulkitmidha\/"}]}},"authors":[{"term_id":10150,"user_id":85668,"is_guest":0,"slug":"pulkitmidha","display_name":"Pulkit Midha - Developer Evangelist","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/pulkit-midha-couchbase.png","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/08\/pulkit-midha-couchbase.png"},"author_category":"1","last_name":"Midha - Developer Evangelist","first_name":"Pulkit","job_title":"","user_url":"","description":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/17494","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/85668"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=17494"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/17494\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/17496"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=17494"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=17494"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=17494"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=17494"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}