{"id":17248,"date":"2025-07-10T13:03:56","date_gmt":"2025-07-10T20:03:56","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=17248"},"modified":"2025-07-10T13:49:34","modified_gmt":"2025-07-10T20:49:34","slug":"designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/","title":{"rendered":"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage"},"content":{"rendered":"<p>In modern data-driven applications, retaining historical documents is essential for compliance, auditing, and cost optimization. However, keeping all data indefinitely in your primary operational database is often unsustainable and expensive.<\/p>\n<p>In this blog post, I\u2019ll walk you through building a <strong>fully serverless archival pipeline<\/strong> that automatically moves documents from <strong>Couchbase<\/strong> to <strong>Amazon S3<\/strong>, using <strong>Couchbase Eventing<\/strong>, <strong>Amazon API Gateway<\/strong>, <strong>SNS<\/strong>, and <strong>AWS Lambda<\/strong>. The architecture demonstrates how to leverage <strong>asynchronous decoupling<\/strong> to improve resilience, scalability, and performance.<\/p>\n<p>By the end of this tutorial, you\u2019ll have a robust, end-to-end solution that reacts to document mutations or TTL-based expirations in Couchbase and archives them efficiently in S3\u2014without any manual intervention.<\/p>\n<h2 style=\"font-weight: 400;\">Architecture overview<\/h2>\n<p>Here\u2019s what the architecture looks like:<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17249\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/arch.jpg\" alt=\"Architecture\" width=\"831\" height=\"401\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/arch.jpg 831w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/arch-300x145.jpg 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/arch-768x371.jpg 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/arch-18x9.jpg 18w\" sizes=\"auto, (max-width: 831px) 100vw, 831px\" \/><\/center>&nbsp;<\/p>\n<p><strong>Flow:<\/strong><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li>Couchbase detects a document condition (like TTL expiry or a custom <code>archive: true<\/code> flag).<\/li>\n<li>A Couchbase Eventing function triggers and sends the document to an API Gateway.<\/li>\n<li>API Gateway forwards the document to an SNS topic.<\/li>\n<li>SNS invokes a Lambda function subscribed to the topic.<\/li>\n<li>Lambda writes the full JSON document into an S3 bucket using a date-based folder structure.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>This setup is decoupled, scalable, and requires zero polling.<\/p>\n<hr \/>\n<h2 style=\"font-weight: 400;\">Why Couchbase Eventing for archival?<\/h2>\n<p><strong>Couchbase Eventing<\/strong> provides a native way to trigger business logic in response to document mutations (creates, updates, deletes) or expirations.<\/p>\n<p>With Eventing, we can:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Monitor specific document types or fields (like <code>archive === true<\/code> and\/or <code>type === logs<\/code>)<\/li>\n<li>React in real time to TTL expirations<\/li>\n<li>Push data out to external services (like AWS) via HTTP calls<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2 style=\"font-weight: 400;\">Writing the Couchbase Eventing function<\/h2>\n<p>Here\u2019s a simplified example of the Couchbase Eventing function we use for archiving documents. The function implements logic to handle two primary scenarios:<\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li><strong>TTL-based Archiving<\/strong>: When a document has an <code>expiration<\/code> set, we register a timer that fires 60 seconds before the TTL. Once the timer expires, the <code>DocTimerCallback<\/code> function is invoked, which then calls the <code>publish(doc, meta)<\/code> function to archive the document.<\/li>\n<li><strong>Flag-based Archiving<\/strong>: Alternatively, if a document includes the field <code>archive: true<\/code>, the function immediately calls <code>publish(doc, meta)<\/code> to archive the document.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>In both cases, the document is sent to an external API Gateway for archiving. If the API response status is either <code>200<\/code> or <code>302<\/code>, the document is explicitly deleted from the source bucket, completing the archive workflow. This provides a flexible mechanism to archive documents either on demand or via TTL-based automation.<\/p>\n<pre class=\"nums:false lang:default decode:true \">function OnUpdate(doc, meta) {\r\n    if (doc.archive &amp;&amp; doc.archive === true){\r\n        log('Archiving document with ID:', meta.id);\r\n        var status = publish(doc, meta);\r\n        if (status === true) {\r\n            delete src[meta.id];\r\n        } else {\r\n            log('Publish failed, document will not be deleted:', meta.id);\r\n        }\r\n    } else if (meta.expiration &gt; 0){\r\n        var nMinsPrior = new Date((meta.expiration - 60) * 1000);\r\n        var currentTime = new Date().getTime();\r\n        log('Time difference (ms): ', currentTime - nMinsPrior);\r\n        if (currentTime &gt; nMinsPrior) {\r\n            log('Within 1 minute of TTL expiry, archiving:', meta.id);\r\n            var publishStatus = publish(doc, meta);\r\n        } else {\r\n            log('Timer set for future archiving:', meta.id);\r\n            createTimer(DocTimerCallback, nMinsPrior, meta.id, meta.id);\r\n        }\r\n    } else {\r\n        log('No archiving conditions met for:', meta.id);\r\n        return;\r\n    }\r\n}\r\n\r\nfunction DocTimerCallback(context) {\r\n    var doc = src[context];\r\n    if (doc) {\r\n        var meta = { id: context };\r\n        var publishStatus = publish(doc, meta);\r\n    } else {\r\n        log('Timer callback failed: document not found for:', context);\r\n    }\r\n}\r\n\r\nfunction publish(doc, meta) {\r\n    try {\r\n        var request = {\r\n            path: 'archive',\r\n            headers: {\r\n                'Content-Type': 'application\/json'\r\n            },\r\n            body: { ...doc, id: meta.id }\r\n        };\r\n        log(\"Sending request:\", request);\r\n        var response = curl('POST', archive2S3, request);\r\n        if (response.status === 200 || response.status === 302) {\r\n            log(\"Publish success for:\", meta.id, \" Response body:\", response.body);\r\n            return true;\r\n        } else {\r\n            log(\"Publish failed with status:\", response.status, \" Request body:\", request);\r\n            return false;\r\n        }\r\n    } catch (e) {\r\n        log(\"Exception during publish:\", e);\r\n        return false;\r\n    }\r\n}\r\n<\/pre>\n<blockquote><p><strong>Note:<\/strong> For performance reasons, we recommend commenting out all the <code>log()<\/code> statements shown above. These logs were included primarily for debugging and development purposes. Excessive logging in production environments can impact performance and increase log storage costs.<\/p><\/blockquote>\n<p>Here is how we defined the settings and bindings, while creating the eventing function.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17256\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/settings.png\" alt=\"\" width=\"983\" height=\"709\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/settings.png 983w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/settings-300x216.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/settings-768x554.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/settings-18x12.png 18w\" sizes=\"auto, (max-width: 983px) 100vw, 983px\" \/><\/p>\n<p>Hit <code>Next<\/code> to create bindings. This is where we will bind the endpoint of our API Gateway, to an alias <code>archive2S3<\/code> and also uses source bucket as alias <code>src<\/code>. Make a note that we used Read\/Write permission for our source bucket as we would like data to be purged out from there.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17250\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/bindings-new.png\" alt=\"\" width=\"983\" height=\"672\" \/><\/p>\n<p>Hit <code>Next<\/code> again and copy\/paste the JS function from above into the window and <code>Save<\/code>. At this point your function is saved but not deployed. Hit three dots and select <code>Deploy<\/code> option to run the eventing function. This is how it would look once function is running.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17252\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/deployed.png\" alt=\"\" width=\"962\" height=\"335\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/deployed.png 962w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/deployed-300x104.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/deployed-768x267.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/deployed-18x6.png 18w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/deployed-800x280.png 800w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/p>\n<hr \/>\n<h2 style=\"font-weight: 400;\">Building the Lambda Function to Archive to S3<\/h2>\n<p>The Lambda function consumes the SNS message and archives the full JSON to an S3 bucket, organized by date.<\/p>\n<h3 style=\"font-weight: 200; font-size: 14px;\">Example Lambda Code<\/h3>\n<pre><code class=\"language-python\">import boto3\r\nimport json\r\nfrom datetime import datetime\r\n\r\ns3 = boto3.client('s3')\r\nbucket_name = 'your-s3-archive-bucket'\r\n\r\ndef lambda_handler(event, context):\r\n    for record in event['Records']:\r\n        msg = json.loads(record['Sns']['Message'])\r\n        doc_id = msg['id']\r\n        content = msg\r\n        now = datetime.utcnow()\r\n        folder = f\"{now.year}\/{now.month}\/{now.day}\"\r\n        key = f\"{folder}\/{doc_id}.json\"\r\n        s3.put_object(\r\n            Bucket=bucket_name,\r\n            Key=key,\r\n            Body=json.dumps(content),\r\n            ContentType='application\/json'\r\n        )\r\n\r\n    return {\r\n        'statusCode': 200,\r\n        'body': 'Archived successfully.'\r\n    }\r\n<\/code><\/pre>\n<p>This results in an S3 object like:<\/p>\n<pre><code>s3:\/\/your-s3-archive-bucket\/2025\/6\/29\/log123.json<\/code><\/pre>\n<hr \/>\n<h2 style=\"font-weight: 400;\">Using SNS to decouple the archival trigger<\/h2>\n<p><strong>SNS (Simple Notification Service)<\/strong> allows multiple services to receive the same message. Here, it passes the archive request to a Lambda function.<\/p>\n<p><strong>Steps:<\/strong><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Create a topic, e.g., <code>ArchiveTriggerTopic<\/code><\/li>\n<li>Allow API Gateway to publish to it via IAM<\/li>\n<li>Subscribe the Lambda function<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><center><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17257\" style=\"border: 1px solid Gainsboro; padding: 10px;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/SNS-Lambda.png\" alt=\"\" width=\"621\" height=\"175\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/SNS-Lambda.png 621w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/SNS-Lambda-300x85.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/SNS-Lambda-18x5.png 18w\" sizes=\"auto, (max-width: 621px) 100vw, 621px\" \/><\/center><br \/>\n<strong>Fixing permissions<\/strong><\/p>\n<p>Ensure API Gateway is allowed to publish to the SNS topic via a trust and access policy:<\/p>\n<h3 style=\"font-weight: 200; font-size: 14px;\">Trust Policy for <code>snsAccess<\/code> Role:<\/h3>\n<pre><code class=\"language-json\">{\r\n  \"Effect\": \"Allow\",\r\n  \"Principal\": {\r\n    \"Service\": \"apigateway.amazonaws.com\"\r\n  },\r\n  \"Action\": \"sts:AssumeRole\"\r\n}\r\n<\/code><\/pre>\n<h3 style=\"font-weight: 200; font-size: 14px;\">Access Policy for the Role:<\/h3>\n<pre><code class=\"language-json\">{\r\n  \"Effect\": \"Allow\",\r\n  \"Action\": \"sns:Publish\",\r\n  \"Resource\": \"arn:aws:sns:us-east-1:account-id:ArchiveTriggerTopic\"\r\n}\r\n<\/code><\/pre>\n<hr \/>\n<h2 style=\"font-weight: 400;\">Setting up API Gateway to accept archive requests<\/h2>\n<p>API Gateway acts as our public endpoint that receives the archive requests and forwards them to SNS.<\/p>\n<p><strong>Key steps:<\/strong><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Create a <strong>REST API<\/strong> in API Gateway.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>From the options provided select <code>REST API<\/code> as it provides integration with the <code>SNS<\/code>\u00a0service.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17264\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-1.png\" alt=\"\" width=\"973\" height=\"253\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-1.png 973w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-1-300x78.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-1-768x200.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-1-18x5.png 18w\" sizes=\"auto, (max-width: 973px) 100vw, 973px\" \/><\/p>\n<p>Give an <code>API name<\/code> and select <code>API endpoint type<\/code> as <code>Regional<\/code>. Hit <code>Create API<\/code> button.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17265\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-2.png\" alt=\"\" width=\"980\" height=\"752\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-2.png 980w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-2-300x230.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-2-768x589.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-2-16x12.png 16w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Set up a <code>POST \/archive<\/code> route.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>On the next <code>Resources<\/code> page, create a resource by hitting <code>Create resource<\/code> button on the left pane.<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17266\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-3.png\" alt=\"\" width=\"721\" height=\"594\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-3.png 721w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-3-300x247.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-3-15x12.png 15w\" sizes=\"auto, (max-width: 721px) 100vw, 721px\" \/><\/center>Give the <code>Resource name<\/code>. I am calling my resource name to be <code>archive<\/code>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17267\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-4.png\" alt=\"\" width=\"994\" height=\"391\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-4.png 994w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-4-300x118.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-4-768x302.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-4-18x7.png 18w\" sizes=\"auto, (max-width: 994px) 100vw, 994px\" \/><\/p>\n<p>Hit <code>Create resource<\/code> button. On the next page, under the <code>Methods<\/code> pane hit <code>Create method<\/code> button. This will allow us to map bunch of settings to our POST method and details about our <strong>SNS<\/strong> service like what <code>AWS Region<\/code> it is running, ARN of the <code>IAM role<\/code> that has the required permission to publish to the SNS topic.<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17269\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-6.png\" alt=\"\" width=\"648\" height=\"828\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-6.png 648w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-6-235x300.png 235w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-6-9x12.png 9w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-6-300x383.png 300w\" sizes=\"auto, (max-width: 648px) 100vw, 648px\" \/><\/center>If you scroll down the page, you&#8217;ll find the <strong data-start=\"141\" data-end=\"172\">URL Query String Parameters<\/strong> section. Here, we&#8217;ll map the ARN of our SNS topic using the parameter name <strong data-start=\"248\" data-end=\"262\"><code data-start=\"250\" data-end=\"260\">TopicArn<\/code><\/strong>. Additionally, we&#8217;ll map <strong data-start=\"288\" data-end=\"301\"><code data-start=\"290\" data-end=\"299\">Message<\/code><\/strong> to <strong data-start=\"305\" data-end=\"330\"><code data-start=\"307\" data-end=\"328\">method.request.body<\/code><\/strong>, which will contain the full payload of our JSON document.<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17272\" style=\"border: 1px solid Gainsboro; text-align: center;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-9.png\" alt=\"\" width=\"655\" height=\"316\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-9.png 1462w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-9-300x145.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-9-1024x494.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-9-768x371.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-9-18x9.png 18w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-GW-9-1320x637.png 1320w\" sizes=\"auto, (max-width: 655px) 100vw, 655px\" \/><\/center>Finally, hit the <code>Save<\/code> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17291\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Method-redacted.png\" alt=\"\" width=\"1021\" height=\"395\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Method-redacted.png 1021w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Method-redacted-300x116.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Method-redacted-768x297.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Method-redacted-18x7.png 18w\" sizes=\"auto, (max-width: 1021px) 100vw, 1021px\" \/><\/p>\n<p>Congratulations, you have just deployed an <strong>API Gateway<\/strong> that can POST your JSON document to the <strong>SNS Topic<\/strong>, which ultimately triggers the <strong>Lambda<\/strong> to write it to <strong>S3<\/strong>.<\/p>\n<hr \/>\n<h2 style=\"font-weight: 400;\">Testing the end-to-end flow<\/h2>\n<p>You can test your pipeline in two ways:<\/p>\n<h3 style=\"font-weight: 200; font-size: 14px;\">First test the API POST method<\/h3>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Hit the <code>Test<\/code> tab and submit a simple JSON, with <code>id<\/code> field as must.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17292\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Test-button-redacted.png\" alt=\"\" width=\"827\" height=\"671\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Test-button-redacted.png 827w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Test-button-redacted-300x243.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Test-button-redacted-768x623.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/API-Test-button-redacted-15x12.png 15w\" sizes=\"auto, (max-width: 827px) 100vw, 827px\" \/><\/p>\n<p>When you hit the <code>Test<\/code> button make sure the log trace shows no error and response status is 200. At this point we have our API endpoint working fine. Next we will test this service from curl.<\/p>\n<h3 style=\"font-weight: 200; font-size: 14px;\">From curl or Postman<\/h3>\n<pre><code class=\"language-bash\">curl -X POST https:\/\/your-api-gateway-url\/archive \\\r\n  -H \"Content-Type: application\/json\" \\\r\n  -d '{\r\n        \"id\": \"hotel::10025\",\r\n        \"type\": \"Hotel\",\r\n        \"message\": \"Archiving via curl\",\r\n        \"archive\": true\r\n      }'\r\n<\/code><\/pre>\n<p>After triggering, check that a corresponding object is created in your S3 bucket.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17254\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-bucket.png\" alt=\"\" width=\"1027\" height=\"453\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-bucket.png 1027w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-bucket-300x132.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-bucket-1024x452.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-bucket-768x339.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-bucket-18x8.png 18w\" sizes=\"auto, (max-width: 1027px) 100vw, 1027px\" \/><\/p>\n<h3 style=\"font-weight: 200; font-size: 14px;\">From Capella using Query Workbench<\/h3>\n<p>To test the setup from the <strong>Capella<\/strong>, insert a document with a <strong>TTL value of 120 seconds<\/strong>.<\/p>\n<pre><code class=\"language-sql\">UPSERT INTO bulk.data.source (KEY, VALUE)\r\nVALUES (\"test::001\", {\"type\": \"test\", \"field\": \"value\"}, {\"expiration\": 2*60});\r\n<\/code><\/pre>\n<p>Execute the above SQL command from query workbench and then wait for the document to appear in the configured <strong>S3 bucket<\/strong> approximately <strong>60 seconds before its expiration<\/strong>, as the Eventing function sets a timer to trigger <strong>one minute prior to the TTL<\/strong>.<\/p>\n<p><center><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-17255 aligncenter\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-eventing.png\" alt=\"\" width=\"617\" height=\"579\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-eventing.png 617w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-eventing-300x282.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/s3-eventing-13x12.png 13w\" sizes=\"auto, (max-width: 617px) 100vw, 617px\" \/><\/center><\/p>\n<hr \/>\n<h2 style=\"font-weight: 400;\">Troubleshooting<\/h2>\n<p>Here are some common issues and how to fix them:<\/p>\n<h3 style=\"font-weight: 200; font-size: 14px;\"><strong>ValidationError<\/strong>: <strong>message must not be null<\/strong><\/h3>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>This usually means the <code>Message<\/code> field sent to SNS is empty.<\/li>\n<li>Ensure your <strong>API Gateway mapping template<\/strong> is correctly extracting the body.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3 style=\"font-weight: 200; font-size: 14px;\"><strong>API Gateway does not have permission to assume the role<\/strong><\/h3>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Confirm that your IAM role has the correct <strong>trust policy<\/strong>.<\/li>\n<li>The role should allow the <code>apigateway.amazonaws.com<\/code> service to assume it.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3 style=\"font-weight: 200; font-size: 14px;\"><strong>Wrong Content-Type in API request<\/strong><\/h3>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>API Gateway only applies mapping templates when the content type is <code>application\/json<\/code>.<\/li>\n<li>Ensure the Couchbase Eventing function (or Postman) sets this header.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3 style=\"font-weight: 200; font-size: 14px;\"><strong>SNS receives escaped or malformed JSON<\/strong><\/h3>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Double-check your use of <code>$util.escapeJavaScript($input.body)<\/code> in the mapping template.<\/li>\n<li>Incorrect escaping can cause issues in downstream Lambda parsing.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3 style=\"font-weight: 200; font-size: 14px;\"><strong>CloudWatch logs to inspect Lambda<\/strong><\/h3>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Monitor the execution trace of Lambda function to confirm everything ran as expected<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17251\" style=\"border: 1px solid Gainsboro;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/cloudwatch.png\" alt=\"\" width=\"1012\" height=\"583\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/cloudwatch.png 1012w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/cloudwatch-300x173.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/cloudwatch-768x442.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/cloudwatch-18x10.png 18w\" sizes=\"auto, (max-width: 1012px) 100vw, 1012px\" \/><\/p>\n<h2 style=\"font-weight: 400;\">Enhancements &amp; best practices<\/h2>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Use <strong>environment variables<\/strong> in Lambda for S3 bucket name and region.<\/li>\n<li>Enable <strong>S3 server-side encryption<\/strong> (SSE-S3 or SSE-KMS) for compliance.<\/li>\n<li>Turn on <strong>S3 versioning<\/strong> to preserve historical copies.<\/li>\n<li>Add <strong>CloudWatch alarms<\/strong> for Lambda errors or API Gateway 5XXs.<\/li>\n<li>Use <strong>SNS fan-out<\/strong> to notify additional consumers (e.g., Kinesis, other Lambdas).<\/li>\n<li>Consider replacing SNS with <strong>direct Lambda integration<\/strong> if you only have one consumer and want simplified permissions.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<h2 style=\"font-weight: 400;\">Conclusion<\/h2>\n<p>In this blog post, we built a robust, real-time document archival pipeline using:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Couchbase Eventing to detect archivable documents<\/li>\n<li>API Gateway to expose a public endpoint<\/li>\n<li>SNS to decouple producers from consumers<\/li>\n<li>Lambda to process and save documents into S3<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>This architecture is fully serverless, scales effortlessly, and is a cost-effective way to offload historical data for retention, compliance, or analysis.<\/p>\n<h2 style=\"font-weight: 400;\">Resources<\/h2>\n<p>To help you dive deeper and expand your knowledge on the technologies used in this pipeline, here are some valuable resources:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/current\/eventing\/eventing-overview.html\" target=\"_blank\" rel=\"noopener\">Couchbase Eventing Overview<\/a><\/li>\n<li><a href=\"https:\/\/docs.aws.amazon.com\/apigateway\/latest\/developerguide\/integrating-api-with-aws-services.html\" target=\"_blank\" rel=\"noopener\">API Gateway to SNS Integration<\/a><\/li>\n<li><a href=\"https:\/\/docs.aws.amazon.com\/lambda\/latest\/dg\/with-s3-example.html\" target=\"_blank\" rel=\"noopener\">Lambda to S3 Example<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In modern data-driven applications, retaining historical documents is essential for compliance, auditing, and cost optimization. However, keeping all data indefinitely in your primary operational database is often unsustainable and expensive. In this blog post, I\u2019ll walk you through building a [&hellip;]<\/p>\n","protected":false},"author":33279,"featured_media":17296,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1821,2225,1816],"tags":[],"ppma_author":[9090],"class_list":["post-17248","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-architecture","category-cloud","category-couchbase-server"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"Learn how to build a fully serverless, stateless data archiving pipeline from Couchbase to Amazon S3 using Eventing, API Gateway, SNS, and AWS Lambda.\" \/>\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\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage\" \/>\n<meta property=\"og:description\" content=\"Learn how to build a fully serverless, stateless data archiving pipeline from Couchbase to Amazon S3 using Eventing, API Gateway, SNS, and AWS Lambda.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-07-10T20:03:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-07-10T20:49:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline-1024x536.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"536\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/\"},\"author\":{\"name\":\"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/21c735da109667147c580bb2cb351c1c\"},\"headline\":\"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage\",\"datePublished\":\"2025-07-10T20:03:56+00:00\",\"dateModified\":\"2025-07-10T20:49:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/\"},\"wordCount\":1297,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png\",\"articleSection\":[\"Couchbase Architecture\",\"Couchbase Capella\",\"Couchbase Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/\",\"name\":\"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png\",\"datePublished\":\"2025-07-10T20:03:56+00:00\",\"dateModified\":\"2025-07-10T20:49:34+00:00\",\"description\":\"Learn how to build a fully serverless, stateless data archiving pipeline from Couchbase to Amazon S3 using Eventing, API Gateway, SNS, and AWS Lambda.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png\",\"width\":2400,\"height\":1256},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage\"}]},{\"@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\/21c735da109667147c580bb2cb351c1c\",\"name\":\"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/5e9708314822fac560c43a5fbdc9b74f\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cb8391905c8ac6ff579c79c90aeaa4e9cf773b87a25e710ee107104c5659deb6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cb8391905c8ac6ff579c79c90aeaa4e9cf773b87a25e710ee107104c5659deb6?s=96&d=mm&r=g\",\"caption\":\"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase\"},\"description\":\"Anuj Sahni is a seasoned cloud and solutions architecture leader with over two decades of experience designing scalable, high-performance enterprise applications across AWS, Azure, and GCP. Currently part of the Capella team at Couchbase, he helps organizations modernize their applications and navigate cloud migration using cloud-native technologies. Prior to Couchbase, Anuj was Principal Product Manager at Oracle, where he led strategic initiatives for Oracle NoSQL Database and Oracle Service Cloud, focusing on distributed, always-available data platforms. He holds a Master\u2019s in Electrical and Computer Engineering from the University of Florida\u00a0and is an active thought leader in the data architecture space.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/anuj-sahni-6a80b617\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/anujsahni\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage - The Couchbase Blog","description":"Learn how to build a fully serverless, stateless data archiving pipeline from Couchbase to Amazon S3 using Eventing, API Gateway, SNS, and AWS Lambda.","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\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/","og_locale":"en_US","og_type":"article","og_title":"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage","og_description":"Learn how to build a fully serverless, stateless data archiving pipeline from Couchbase to Amazon S3 using Eventing, API Gateway, SNS, and AWS Lambda.","og_url":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/","og_site_name":"The Couchbase Blog","article_published_time":"2025-07-10T20:03:56+00:00","article_modified_time":"2025-07-10T20:49:34+00:00","og_image":[{"width":1024,"height":536,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline-1024x536.png","type":"image\/png"}],"author":"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/"},"author":{"name":"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/21c735da109667147c580bb2cb351c1c"},"headline":"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage","datePublished":"2025-07-10T20:03:56+00:00","dateModified":"2025-07-10T20:49:34+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/"},"wordCount":1297,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png","articleSection":["Couchbase Architecture","Couchbase Capella","Couchbase Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/","url":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/","name":"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png","datePublished":"2025-07-10T20:03:56+00:00","dateModified":"2025-07-10T20:49:34+00:00","description":"Learn how to build a fully serverless, stateless data archiving pipeline from Couchbase to Amazon S3 using Eventing, API Gateway, SNS, and AWS Lambda.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2025\/07\/blog-data-pipeline.png","width":2400,"height":1256},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/designing-a-serverless-data-archiving-pipeline-from-couchbase-to-cloud-storage\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Designing a Serverless Data Archiving Pipeline from Couchbase to Cloud Storage"}]},{"@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\/21c735da109667147c580bb2cb351c1c","name":"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/5e9708314822fac560c43a5fbdc9b74f","url":"https:\/\/secure.gravatar.com\/avatar\/cb8391905c8ac6ff579c79c90aeaa4e9cf773b87a25e710ee107104c5659deb6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cb8391905c8ac6ff579c79c90aeaa4e9cf773b87a25e710ee107104c5659deb6?s=96&d=mm&r=g","caption":"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase"},"description":"Anuj Sahni is a seasoned cloud and solutions architecture leader with over two decades of experience designing scalable, high-performance enterprise applications across AWS, Azure, and GCP. Currently part of the Capella team at Couchbase, he helps organizations modernize their applications and navigate cloud migration using cloud-native technologies. Prior to Couchbase, Anuj was Principal Product Manager at Oracle, where he led strategic initiatives for Oracle NoSQL Database and Oracle Service Cloud, focusing on distributed, always-available data platforms. He holds a Master\u2019s in Electrical and Computer Engineering from the University of Florida\u00a0and is an active thought leader in the data architecture space.","sameAs":["https:\/\/www.linkedin.com\/in\/anuj-sahni-6a80b617"],"url":"https:\/\/www.couchbase.com\/blog\/author\/anujsahni\/"}]}},"authors":[{"term_id":9090,"user_id":33279,"is_guest":0,"slug":"anujsahni","display_name":"Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/cb8391905c8ac6ff579c79c90aeaa4e9cf773b87a25e710ee107104c5659deb6?s=96&d=mm&r=g","author_category":"1","last_name":"Sahni, Cloud and Solutions Architecture Leader, Couchbase","first_name":"Anuj","job_title":"","user_url":"https:\/\/www.linkedin.com\/in\/anuj-sahni-6a80b617","description":"<p data-start=\"231\" data-end=\"963\"><strong>Anuj Sahni<\/strong> is a seasoned cloud and solutions architecture leader with over two decades of experience designing scalable, high-performance enterprise applications across AWS, Azure, and GCP. Currently part of the <strong>Capella team at Couchbase<\/strong>, he helps organizations modernize their applications and navigate cloud migration using cloud-native technologies.<\/p>\r\n<p data-start=\"231\" data-end=\"963\">Prior to Couchbase, Anuj was <strong>Principal Product Manager at Oracle<\/strong>, where he led strategic initiatives for Oracle NoSQL Database and Oracle Service Cloud, focusing on distributed, always-available data platforms. He holds a <strong>Master\u2019s in Electrical and Computer Engineering<\/strong> from the <strong>University of Florida<\/strong>\u00a0and is an active thought leader in the data architecture space.<\/p>"}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/17248","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\/33279"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=17248"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/17248\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/17296"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=17248"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=17248"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=17248"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=17248"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}