<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Saif Ali</title>
    <description>The latest articles on DEV Community by Saif Ali (@sali_ac161a1b71406354896c).</description>
    <link>https://dev.to/sali_ac161a1b71406354896c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3780544%2F353acf11-059d-471c-a779-825d98da6c00.png</url>
      <title>DEV Community: Saif Ali</title>
      <link>https://dev.to/sali_ac161a1b71406354896c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sali_ac161a1b71406354896c"/>
    <language>en</language>
    <item>
      <title>The best way to deploy an HTML website and API to the cloud</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sat, 22 Aug 2026 18:11:14 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/the-best-way-to-deploy-an-html-website-and-api-to-the-cloud-4e4e</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/the-best-way-to-deploy-an-html-website-and-api-to-the-cloud-4e4e</guid>
      <description>&lt;h2&gt;
  
  
  The best way to deploy an HTML website and API to the cloud
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Published:&lt;/strong&gt; August 10, 2026&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Deployments · Fundamentals&lt;br&gt;
&lt;strong&gt;Reading time:&lt;/strong&gt; 6 minutes&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; NEXUS AI Team&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; if your HTML and your API are small enough to ship together, put them in one server (a static folder plus a few routes) and deploy that as a single container. It is one URL, no CORS, no second bill, and it fits on a free tier. Split them into two separately-hosted services only when you actually need independent scaling or a different tech stack for each side. This post covers both paths, with the commands for each.&lt;/p&gt;


&lt;h2&gt;
  
  
  The three ways people actually do this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. One server, two jobs.&lt;/strong&gt; An Express, FastAPI, or Flask app that serves your &lt;code&gt;index.html&lt;/code&gt; (and any CSS/JS) as static files from one route, and your API as JSON routes on the same port. One deploy, one URL, one process. This is the right default for a portfolio site, an internal tool, a small SaaS MVP, or anything where the frontend and backend ship together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Two hosts, one app.&lt;/strong&gt; The HTML lives on a static host (a CDN edge network), the API lives on a separate compute host, and the frontend calls the API's URL over HTTPS with CORS enabled. This is the classic Vercel/Netlify-plus-Render/Railway pattern. It buys you independent scaling and a CDN for the static assets, at the cost of two dashboards, two bills, and a CORS config to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Raw cloud primitives.&lt;/strong&gt; S3 or Cloud Storage plus a CDN in front for the HTML, then Lambda/Cloud Functions or a VM for the API. Full control, the most setup work, and you own the plumbing (TLS certs, IAM, deploy scripts) yourself.&lt;/p&gt;

&lt;p&gt;Most people asking "what's the best way to deploy my HTML site and API" have something closer to option 1 in mind and don't need the operational overhead of options 2 or 3 yet.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Setup time&lt;/th&gt;
&lt;th&gt;Cost to start&lt;/th&gt;
&lt;th&gt;Scaling&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One server, two jobs&lt;/td&gt;
&lt;td&gt;~5 minutes&lt;/td&gt;
&lt;td&gt;Free tier fits&lt;/td&gt;
&lt;td&gt;Vertical, then horizontal&lt;/td&gt;
&lt;td&gt;MVPs, internal tools, small apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two hosts, one app&lt;/td&gt;
&lt;td&gt;~15–30 minutes&lt;/td&gt;
&lt;td&gt;Two free tiers, or one paid&lt;/td&gt;
&lt;td&gt;Independent per side&lt;/td&gt;
&lt;td&gt;Apps that outgrew #1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raw cloud primitives&lt;/td&gt;
&lt;td&gt;Hours to days&lt;/td&gt;
&lt;td&gt;Pay-as-you-go&lt;/td&gt;
&lt;td&gt;Fully manual&lt;/td&gt;
&lt;td&gt;Teams with existing cloud infra&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Option 1: deploy HTML + API together as one container
&lt;/h2&gt;

&lt;p&gt;This is the fastest path and the one this section walks through end to end using NEXUS AI, which auto-detects a static folder next to an API server and builds a single production Dockerfile for it — no Dockerfile required on your side.&lt;/p&gt;
&lt;h3&gt;
  
  
  Project layout
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-app/
  public/
    index.html
    style.css
    app.js
  server.js        ← serves /public and the /api routes
  package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/health&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/items&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;First item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Listening on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Deploy it
&lt;/h3&gt;

&lt;p&gt;Install the CLI and log in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://nexusai.run/install.sh | bash    &lt;span class="c"&gt;# Linux&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://nexusai.run/install-mac.sh | bash &lt;span class="c"&gt;# macOS&lt;/span&gt;
nexus auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push the repo to GitHub, then deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/you/my-app.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; express &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEXUS AI builds a production image, opens a public HTTPS URL through Traefik, and streams build logs while it works. When it finishes, &lt;code&gt;https://my-app.nexusai.run&lt;/code&gt; serves the HTML at &lt;code&gt;/&lt;/code&gt; and JSON at &lt;code&gt;/api/*&lt;/code&gt; from the same origin. No CORS headers needed because it is one origin.&lt;/p&gt;

&lt;p&gt;If your HTML has no server logic at all (pure static, no API in the same process), skip the Express wrapper and deploy the folder directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/you/my-static-site.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-static-site &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; static &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEXUS AI detects the plain &lt;code&gt;index.html&lt;/code&gt; and serves it with nginx.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add environment variables and a custom domain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus secret create DATABASE_URL &lt;span class="s2"&gt;"postgres://..."&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; my-app
nexus domain add my-app yourdomain.com
nexus domain verify my-app &amp;lt;domain-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That covers the common case: one small app, one deploy, one bill, free tier eligible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option 2: split the static site and the API into two services
&lt;/h2&gt;

&lt;p&gt;Reach for this once the frontend and backend genuinely need to scale, deploy, or fail independently — a marketing site that gets Hacker-News-front-page traffic spikes while the API stays flat, or a frontend team shipping on a different cadence than the backend team.&lt;/p&gt;

&lt;p&gt;Deploy the API on its own:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/you/my-api.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; express &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the static HTML as a second service in the same project (this needs a plan with more than one active deployment — see the FAQ below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/you/my-frontend.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-frontend &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; static &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point the frontend's fetch calls at the API's public URL, and enable CORS on the API for the frontend's origin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// my-api/server.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://my-frontend.nexusai.run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// my-frontend/app.js&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://my-api.nexusai.run/api/items&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each service now scales, redeploys, and rolls back independently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy scale my-api 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also mix providers here: keep the static frontend on a CDN-first host (Vercel, Netlify, GitHub Pages) for free and put only the API on NEXUS AI. Point the frontend's &lt;code&gt;NEXT_PUBLIC_API_URL&lt;/code&gt; (or equivalent) at the NEXUS AI URL and enable CORS the same way.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do I need to write a Dockerfile for a plain HTML site?&lt;/strong&gt;&lt;br&gt;
No. NEXUS AI detects an &lt;code&gt;index.html&lt;/code&gt; with no build manifest and serves it with nginx automatically. If you have a build step (Vite, React, Vue), it detects the framework and runs the production build instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My API needs a database. Does that change the deploy?&lt;/strong&gt;&lt;br&gt;
No extra service to wire up separately. Add &lt;code&gt;--services postgresql&lt;/code&gt; (or &lt;code&gt;mysql&lt;/code&gt;, &lt;code&gt;mongodb&lt;/code&gt;, &lt;code&gt;redis&lt;/code&gt;) to the same &lt;code&gt;nexus deploy source&lt;/code&gt; command and NEXUS AI provisions the database alongside your app in the same deploy, with &lt;code&gt;DATABASE_URL&lt;/code&gt; injected automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use a custom domain instead of the &lt;code&gt;.nexusai.run&lt;/code&gt; subdomain?&lt;/strong&gt;&lt;br&gt;
Yes, on any paid plan. &lt;code&gt;nexus domain add &amp;lt;deployment&amp;gt; yourdomain.com&lt;/code&gt;, then verify the DNS record NEXUS AI gives you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a free tier?&lt;/strong&gt;&lt;br&gt;
Yes. The Free plan includes one active deployment on the NEXUS AI managed cloud, no credit card required — enough for the single-server pattern in Option 1. Running the two-service split in Option 2 on NEXUS AI for both halves needs a plan that allows more than one active deployment (Pro and above); running just the API on NEXUS AI Free while the static frontend sits on a separate free static host works within the Free plan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this handle HTTPS automatically?&lt;/strong&gt;&lt;br&gt;
Yes. Every deployment gets a public HTTPS URL through Traefik by default, and custom domains get certificates provisioned automatically once DNS verification passes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I deploy from the GitHub UI instead of the CLI?&lt;/strong&gt;&lt;br&gt;
Yes. Connect your GitHub account from the NEXUS AI dashboard, select a repo and branch, and enable auto-deploy so every push to that branch redeploys automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if I'd rather describe the app in plain English and skip writing server.js myself?&lt;/strong&gt;&lt;br&gt;
Use the AI App Builder instead: describe the HTML site and the API you want in chat, review the generated files and live preview, then deploy from the same dashboard.&lt;/p&gt;




&lt;p&gt;For an app with a real database, background workers, and file storage in addition to the HTML + API pair, see &lt;a href="https://nexusai.run/blog/from-v0-prototype-to-production-database-in-5-minutes" rel="noopener noreferrer"&gt;From v0 prototype to production database in 5 minutes&lt;/a&gt; and &lt;a href="https://nexusai.run/blog/deploy-full-stack-python-postgres-redis-workers-5-minutes" rel="noopener noreferrer"&gt;Deploy a full-stack Python app with Postgres, Redis, and workers in 5 minutes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nexusai.run/register" rel="noopener noreferrer"&gt;Start free.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>staticsite</category>
      <category>api</category>
      <category>express</category>
    </item>
    <item>
      <title>Enterprise vibe coding: the governance framework for shipping AI-generated apps to production</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sat, 22 Aug 2026 18:09:02 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/enterprise-vibe-coding-the-governance-framework-for-shipping-ai-generated-apps-to-production-32j1</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/enterprise-vibe-coding-the-governance-framework-for-shipping-ai-generated-apps-to-production-32j1</guid>
      <description>&lt;h1&gt;
  
  
  Enterprise vibe coding: the governance framework for shipping AI-generated apps to production
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Published:&lt;/strong&gt; August 22, 2026&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Enterprise · AI Deployments&lt;br&gt;
&lt;strong&gt;Reading time:&lt;/strong&gt; 9 minutes&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; NEXUS AI Team&lt;/p&gt;




&lt;p&gt;Gartner forecasts that 40% of new enterprise production software will be built using vibe coding techniques by 2028. A 2026 scan of more than 1,400 live vibe-coded applications found that 65% already had a security issue, and 58% shipped with at least one critical vulnerability. Those two numbers describe the same industry moving in opposite directions at once: adoption is outrunning governance.&lt;/p&gt;

&lt;p&gt;This post covers what a governance framework for enterprise vibe coding actually looks like, the five controls it needs, and where most teams get it wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is enterprise vibe coding?
&lt;/h2&gt;

&lt;p&gt;Enterprise vibe coding is the practice of using natural-language prompts to generate application code, then governing that code through mandatory review, access control, and audit before it reaches production, rather than letting it ship straight from a prompt to a live endpoint. The term (coined by Andrej Karpathy in early 2025) originally described a fast, low-friction way for one person to build a prototype. What "enterprise" adds is the governance layer prototyping was never built for: staging environments, encrypted secrets, role-based access, and a record of who approved what.&lt;/p&gt;

&lt;p&gt;That distinction matters because the adoption curve and the risk curve are not moving together.&lt;/p&gt;




&lt;h2&gt;
  
  
  The governance gap, in three numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;40%&lt;/strong&gt; of new enterprise production software will be built using vibe coding techniques by 2028, according to &lt;a href="https://www.ciodive.com/news/vibe-coding-enterprise-CIO-strategy/750349/" rel="noopener noreferrer"&gt;Gartner's May 2025 report "Why Vibe Coding Needs to Be Taken Seriously," as reported by CIO Dive&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;65%&lt;/strong&gt; of vibe-coded production applications had a security issue, in a 2026 scan of more than 1,400 live apps by the API security firm Escape.tech, &lt;a href="https://labs.cloudsecurityalliance.org/research/csa-research-note-ai-generated-code-security-vibe-coding-202/" rel="noopener noreferrer"&gt;reported via a Cloud Security Alliance research note&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;58%&lt;/strong&gt; of those same applications shipped with at least one &lt;em&gt;critical&lt;/em&gt; vulnerability, including hardcoded secrets and exposed personally identifiable information, per the same research note.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enterprises are not waiting for a governance model before they start vibe coding internal tools, dashboards, and customer-facing features. They already have prototypes running in places IT never reviewed: a developer's laptop, a personal cloud account, a container nobody on the security team knows exists.&lt;/p&gt;

&lt;p&gt;The fix is not to slow down adoption. It is to give the workflow teams already use a governed path to production, instead of asking them to abandon a workflow that is, by every account, faster than what it replaced.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "enterprise-ready" actually requires
&lt;/h2&gt;

&lt;p&gt;Most vibe coding tools are optimized for the first 90% of the problem: turning a prompt into working code fast. Enterprise readiness is almost entirely about the remaining 10%, the part that happens after the code works and before it is trusted with real users or real data.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Consumer vibe-coding tools&lt;/th&gt;
&lt;th&gt;Enterprise-ready platform&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where it runs&lt;/td&gt;
&lt;td&gt;Vendor-hosted, shared infrastructure&lt;/td&gt;
&lt;td&gt;Your own AWS, Google Cloud, or Azure account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets handling&lt;/td&gt;
&lt;td&gt;Frequently hardcoded into generated code&lt;/td&gt;
&lt;td&gt;Encrypted secrets vault, injected at runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change review&lt;/td&gt;
&lt;td&gt;Rare or none — the agent applies changes directly&lt;/td&gt;
&lt;td&gt;Every schema and infrastructure change reviewed by a human before it ships&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access control&lt;/td&gt;
&lt;td&gt;Single shared account, no role separation&lt;/td&gt;
&lt;td&gt;Role-based access control (RBAC) with least-privilege defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit trail&lt;/td&gt;
&lt;td&gt;Rare or none&lt;/td&gt;
&lt;td&gt;Full audit log of every automated action, attributable to a user or agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback&lt;/td&gt;
&lt;td&gt;Manual, if available at all&lt;/td&gt;
&lt;td&gt;One-click versioned rollback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data residency&lt;/td&gt;
&lt;td&gt;Decided by the vendor&lt;/td&gt;
&lt;td&gt;Decided by the customer (on-premises, private cloud, or hybrid)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of these controls are exotic. They are the same controls that already exist for human-written code in any organization with a functioning SDLC. The gap is that most vibe coding tools were built for individual prototyping, where none of this mattered, and enterprises adopted them anyway because the alternative, a developer manually gluing infrastructure together, was slower.&lt;/p&gt;




&lt;h2&gt;
  
  
  A five-control governance framework
&lt;/h2&gt;

&lt;p&gt;Enterprises that have gotten ahead of the governance gap generally converge on the same five controls, applied before code reaches a production endpoint:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define which tools are approved, and for what.&lt;/strong&gt; Not every vibe coding tool should be allowed to touch every kind of workload. Internal dashboards and low-risk operational tools are a reasonable starting point; anything touching regulated data (PHI, PCI, PII) needs a platform with compliance controls attached by default, not bolted on later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Require human review before infrastructure or schema changes ship.&lt;/strong&gt; An agent proposing a database migration or an IAM policy change is fine. An agent applying it unilaterally is how you end up as a statistic in the next vulnerability scan. Review gates are the single highest-leverage control in this list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put secrets in a vault, never in generated code.&lt;/strong&gt; Hardcoded credentials are one of the most consistently identified issues in scans of AI-generated code. An encrypted secrets vault with runtime injection removes the failure mode entirely rather than relying on the agent to remember not to do it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log every automated action.&lt;/strong&gt; If an agent deployed it, scaled it, or rolled it back, that action needs to be attributable and reviewable after the fact. Security and compliance teams cannot govern what they cannot see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy inside a perimeter you control.&lt;/strong&gt; For regulated workloads especially, "which cloud account is this actually running in" needs a straightforward answer. Vendor-hosted, shared infrastructure makes that answer harder than it needs to be.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Organizations that put structured frameworks like this in place report meaningfully faster remediation when something does go wrong, without giving up the development speed that made vibe coding worth adopting in the first place.&lt;/p&gt;




&lt;h2&gt;
  
  
  How NEXUS AI implements each control
&lt;/h2&gt;

&lt;p&gt;NEXUS AI extends the same natural-language workflow teams already use to generate an app through deployment, with these five controls attached by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Approved-tool boundary:&lt;/strong&gt; the &lt;a href="https://nexusai.run/ai-app-builder" rel="noopener noreferrer"&gt;AI App Builder&lt;/a&gt; generates and verifies code in an isolated development sandbox before anything is deployed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review gates:&lt;/strong&gt; the database intelligence layer lets an agent propose schema fixes from runtime logs, but every change is reviewed by a human before it is applied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets vault:&lt;/strong&gt; every deployment gets an AES-256-GCM encrypted secrets vault, with values injected at runtime and never written into the container image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit log:&lt;/strong&gt; every automated action, by a user or an MCP-connected agent, is recorded and reviewable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your own cloud, or ours:&lt;/strong&gt; &lt;a href="https://nexusai.run/enterprise" rel="noopener noreferrer"&gt;NEXUS AI Enterprise&lt;/a&gt; deploys on-premises, inside your own AWS, Google Cloud, or Azure account, or in a hybrid mix of both. Shared, multi-tenant infrastructure is available but never mandatory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full breakdown on the &lt;a href="https://nexusai.run/vibe-coding-for-enterprise" rel="noopener noreferrer"&gt;vibe coding for the enterprise&lt;/a&gt; page, or the compliance controls on the &lt;a href="https://nexusai.run/security" rel="noopener noreferrer"&gt;security&lt;/a&gt; and &lt;a href="https://nexusai.run/hipaa-compliance" rel="noopener noreferrer"&gt;HIPAA and compliance&lt;/a&gt; pages if the workload touches regulated data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common mistakes enterprises make with vibe coding
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Treating governance as a launch blocker instead of a default.&lt;/strong&gt; Bolting review, secrets management, and audit logging onto an existing vibe-coded app after the fact is far more expensive than starting with a platform that ships them by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Banning the workflow instead of governing it.&lt;/strong&gt; Prohibition policies get worked around. Teams that need to move fast will use an ungoverned tool on a personal account rather than wait for IT to approve a governed one. The fix is to make the governed path the fast path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming code review catches what secret scanning would.&lt;/strong&gt; Human reviewers are good at logic and architecture; they are inconsistent at spotting a hardcoded API key in a 400-line diff. Automated secrets detection and a vault are not optional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipping the audit log because "nothing has gone wrong yet."&lt;/strong&gt; The value of an audit trail is realized entirely after something goes wrong. By then, it is too late to start logging.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What percentage of AI-generated code has security vulnerabilities?&lt;/strong&gt;&lt;br&gt;
A 2026 scan of over 1,400 vibe-coded production applications by Escape.tech, reported via a Cloud Security Alliance research note, found that 65% had a security issue and 58% shipped with at least one critical vulnerability, including exposed secrets and personally identifiable information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much enterprise software will actually be vibe coded?&lt;/strong&gt;&lt;br&gt;
Gartner's May 2025 report "Why Vibe Coding Needs to Be Taken Seriously" forecasts that 40% of new enterprise production software will be built using vibe coding techniques by 2028.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is vibe coding safe to use for production applications?&lt;/strong&gt;&lt;br&gt;
Not by default. Published scans of vibe-coded apps show high rates of security issues and critical vulnerabilities when code goes straight from prompt to production with no review layer. Enterprise vibe coding platforms close that gap with mandatory human review, an encrypted secrets vault, RBAC, and a full audit log before anything ships.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does "vibe coding for the enterprise" mean, specifically?&lt;/strong&gt;&lt;br&gt;
It means giving teams that already use AI to generate application code a sanctioned, governed path to production, instead of prototypes running on laptops or personal cloud accounts outside IT review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does adding governance controls slow down vibe coding?&lt;/strong&gt;&lt;br&gt;
Not meaningfully, if the controls are built into the platform rather than added as a separate process. A review gate on infrastructure changes and an automatic secrets vault add seconds, not days, when they are part of the deploy workflow instead of a follow-up ticket.&lt;/p&gt;




&lt;p&gt;The gap between vibe coding adoption and vibe coding governance is not going to close on its own. It closes when the platform generating the code is the same platform enforcing review, secrets management, access control, audit logging, and deployment into a cloud account the enterprise actually controls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nexusai.run/vibe-coding-for-enterprise" rel="noopener noreferrer"&gt;See vibe coding for the enterprise applied.&lt;/a&gt; Or &lt;a href="https://nexusai.run/contact" rel="noopener noreferrer"&gt;talk to sales&lt;/a&gt; about a governed path to production for your team.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>enterprise</category>
      <category>governance</category>
      <category>aicodegeneration</category>
    </item>
    <item>
      <title>NEXUS AI RBAC Deep Dive</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:45:44 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-rbac-deep-dive-5m9</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-rbac-deep-dive-5m9</guid>
      <description>&lt;h2&gt;
  
  
  RBAC deep dive: roles, scopes, and least privilege
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Published:&lt;/strong&gt; August 15, 2026&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Security · Platform&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Reading time:&lt;/strong&gt; 14 minutes&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; NEXUS AI Team&lt;/p&gt;

&lt;p&gt;A developer leaves the company on Friday. By Monday, their credentials still open three production deployments, two billing pages, and a secrets vault they haven't touched in four months.&lt;/p&gt;

&lt;p&gt;That's not a people problem. That's an access model problem.&lt;/p&gt;

&lt;p&gt;Role-Based Access Control (RBAC) is how NEXUS AI answers the question every engineering org eventually asks: &lt;em&gt;who can do what, to which resources, and how do we prove it?&lt;/em&gt; This post goes deep the role hierarchy, how scopes layer on top of roles, how least privilege works in practice, and how to design an access model your team will actually maintain.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why RBAC matters more as your team scales
&lt;/h2&gt;

&lt;p&gt;When it's just you, every door being open is convenient. When you have a team of 12 across three environments, every door being open is a liability.&lt;/p&gt;

&lt;p&gt;The breach surface for a SaaS product running on cloud infrastructure is rarely the infrastructure itself. It's the humans and automated systems that have standing access to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A contractor with &lt;code&gt;admin&lt;/code&gt; access granted for a two week engagement and never revoked.&lt;/li&gt;
&lt;li&gt;A CI/CD token with full &lt;code&gt;secrets:write&lt;/code&gt; permission because it was "easier to set up that way."&lt;/li&gt;
&lt;li&gt;A junior developer who can redeploy production because the staging role got copy-pasted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NEXUS AI's RBAC system is designed to make the right permission easy to grant and hard to accidentally expand. Least privilege is the default, not a setting you have to configure.&lt;/p&gt;
&lt;h2&gt;
  
  
  The role hierarchy
&lt;/h2&gt;

&lt;p&gt;NEXUS AI defines four built-in roles. They are ordered by permission level each role is a strict superset of the one below it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Who it's for&lt;/th&gt;
&lt;th&gt;What it controls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Viewer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stakeholders, auditors, QA observers&lt;/td&gt;
&lt;td&gt;Read-only access to deployments, logs, and metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Developer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Engineers doing day-to-day deployment work&lt;/td&gt;
&lt;td&gt;Deploy, redeploy, rollback; read secret names (not values)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Admin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Team leads, platform engineers&lt;/td&gt;
&lt;td&gt;Full control of deployments, secrets, tokens, and members&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Owner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Founder, CTO, or designated security lead&lt;/td&gt;
&lt;td&gt;Everything Admin can do + delete the organization&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One organization has exactly one Owner. Ownership can be transferred, but not duplicated. This prevents the "everyone is an Owner" pattern that makes incident response a guessing game.&lt;/p&gt;
&lt;h3&gt;
  
  
  Viewer
&lt;/h3&gt;

&lt;p&gt;Viewers can observe nothing more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ View deployment status (running, stopped, failed)
✓ Read build and runtime logs
✓ See deployment metadata (region, container count, uptime)
✓ View audit log summaries
✗ Trigger any action (deploy, redeploy, rollback, stop)
✗ See secret names or values
✗ Create or revoke Access Tokens
✗ Invite or remove team members
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use Viewer for: product managers monitoring deploy status, customer success checking uptime, external auditors reviewing activity logs, read-only access for contractors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Developer
&lt;/h3&gt;

&lt;p&gt;Developers can act on deployments. They cannot change platform configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Everything Viewer can do
✓ Deploy, redeploy, rollback, stop deployments
✓ View secret names (DATABASE_URL, STRIPE_KEY) never values
✓ Create Access Tokens scoped to deploy:read and deploy:write only
✗ Create, update, or delete secrets
✗ Create tokens with admin or secrets:write scope
✗ Invite or remove organization members
✗ View billing or usage data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Developer can push code and redeploy. They cannot change the secrets their code reads. The separation is intentional: it means a Developer-level compromise cannot extract production credentials, only trigger a redeploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Admin
&lt;/h3&gt;

&lt;p&gt;Admins own the platform configuration for an organization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Everything Developer can do
✓ Create, update, and delete secrets
✓ Create Access Tokens with any scope
✓ Invite members and assign roles (up to Admin)
✓ View and export audit logs
✓ Manage domains, billing, and usage
✗ Delete the organization
✗ Transfer ownership
✗ Grant Owner role to another member
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Limit Admin to people who actually need to configure secrets or onboard team members. In a 10-person startup, that's usually two or three people. In a 100-person company, it's a dedicated platform team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Owner
&lt;/h3&gt;

&lt;p&gt;The Owner role is structurally different from Admin it's not just "more permissions," it's accountability. Only one member holds it, and it carries the ability to perform irreversible actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Everything Admin can do
✓ Delete the organization and all its resources
✓ Transfer ownership to another Admin
✓ Access all historical audit logs (including deleted members)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Owner should be the person who is accountable for the business not necessarily the most technical. At a startup, that's the founding engineer or CTO. At an enterprise, it's the platform owner or CISO-designated lead.&lt;/p&gt;




&lt;h2&gt;
  
  
  How scopes work
&lt;/h2&gt;

&lt;p&gt;Roles define what a &lt;em&gt;human&lt;/em&gt; can do. Scopes define what a &lt;em&gt;token&lt;/em&gt; can do.&lt;/p&gt;

&lt;p&gt;When a Developer (or Admin) creates an Access Token, they can grant that token any scope up to but not exceeding their own permissions. A Developer cannot create a token with &lt;code&gt;secrets:write&lt;/code&gt; scope, because Developers cannot write secrets directly.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;scope containment&lt;/strong&gt;: tokens cannot be a privilege escalation vector.&lt;/p&gt;

&lt;h3&gt;
  
  
  The full scope table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Read/Write&lt;/th&gt;
&lt;th&gt;What it permits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deploy:read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;View status, logs, metadata for deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deploy:write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Create, redeploy, rollback, scale, stop deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;secrets:read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;List secret names for a deployment (never values)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;secrets:write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Create, update, delete secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tokens:read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;List tokens and their metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tokens:write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Create and revoke Access Tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;members:read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;List organization members and their roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;members:write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Invite, remove, and change roles of members&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;billing:read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;View usage statistics and invoices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;billing:write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Update billing plan and payment method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;logs:read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;Read build logs, runtime logs, and audit logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Full access equivalent to Admin role&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Scopes compose. A CI token for a deployment pipeline typically needs &lt;code&gt;deploy:write&lt;/code&gt; and nothing else. A token for a read-only monitoring integration needs &lt;code&gt;deploy:read&lt;/code&gt; and &lt;code&gt;logs:read&lt;/code&gt;. An MCP integration for an AI agent doing deployment management might need &lt;code&gt;deploy:read,deploy:write,logs:read&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a precisely scoped token
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# CI/CD: deploy-only, expires in 90 days&lt;/span&gt;
nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"github-actions-prod"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:write &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires&lt;/span&gt; 90d

&lt;span class="c"&gt;# Monitoring integration: read-only, no expiry (rotate quarterly via calendar)&lt;/span&gt;
nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"datadog-integration"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:read,logs:read

&lt;span class="c"&gt;# AI agent with deployment management access&lt;/span&gt;
nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"claude-mcp-agent"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:read,deploy:write,logs:read &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires&lt;/span&gt; 30d

&lt;span class="c"&gt;# Admin token for a one time onboarding script (delete immediately after use)&lt;/span&gt;
nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"onboarding-script-2026-04-21"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; admin &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires&lt;/span&gt; 1d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last example a short-lived &lt;code&gt;admin&lt;/code&gt; token for a specific script, destroyed after use is exactly how temporary elevated access should work. No standing privileged access. No "just in case" tokens that accumulate over months.&lt;/p&gt;




&lt;h2&gt;
  
  
  Least privilege in practice
&lt;/h2&gt;

&lt;p&gt;Least privilege is not a policy you write. It's a discipline you build into your provisioning process. Here's what it looks like in a real NEXUS AI team across three common scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 1: Onboarding a new backend engineer
&lt;/h3&gt;

&lt;p&gt;Wrong approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New hire → Admin role → "they'll need it eventually"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New hire → Developer role
Week 1: pair with an Admin for any secrets work
Month 3: reassess do they actually need Admin? (usually no)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Developer role covers 95% of what an active engineer does: deploy, redeploy, check logs, rollback a bad release. Secret creation is rare and can go through an Admin without slowing anyone down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 2: Setting up a GitHub Actions pipeline
&lt;/h3&gt;

&lt;p&gt;Wrong approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus token create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"github-actions"&lt;/span&gt; &lt;span class="nt"&gt;--scopes&lt;/span&gt; admin
&lt;span class="c"&gt;# Stored in GitHub secrets as NEXUS_API_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# One token per environment, deploy:write only&lt;/span&gt;
nexus token create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"github-actions-staging"&lt;/span&gt; &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:write &lt;span class="nt"&gt;--expires&lt;/span&gt; 90d
nexus token create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"github-actions-prod"&lt;/span&gt; &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:write &lt;span class="nt"&gt;--expires&lt;/span&gt; 90d

&lt;span class="c"&gt;# Store each in the corresponding GitHub environment secret&lt;/span&gt;
&lt;span class="c"&gt;# github.com/org/repo → Settings → Environments → staging → NEXUS_API_KEY&lt;/span&gt;
&lt;span class="c"&gt;# github.com/org/repo → Settings → Environments → production → NEXUS_API_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment scoped tokens mean a staging pipeline compromise cannot touch production. The &lt;code&gt;deploy:write&lt;/code&gt; scope means the pipeline can redeploy but cannot read or modify secrets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 3: Granting an external contractor temporary access
&lt;/h3&gt;

&lt;p&gt;Wrong approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Contractor → Admin role → "we'll remove it when they're done"
(They're done. It's still there. Six months later: breach.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Invite as Viewer they can observe, not act&lt;/span&gt;
nexus member invite contractor@agency.com &lt;span class="nt"&gt;--role&lt;/span&gt; Viewer

&lt;span class="c"&gt;# If they need to trigger deploys, create a scoped token with explicit expiry&lt;/span&gt;
nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"contractor-agency-q2-2026"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:write &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires&lt;/span&gt; 30d

&lt;span class="c"&gt;# Deliver the token via a secure channel. Calendar reminder for 29 days out.&lt;/span&gt;
&lt;span class="c"&gt;# At project end: revoke the token and remove the member&lt;/span&gt;
nexus token revoke tok_01HX9...
nexus member remove contractor@agency.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The token expires automatically even if you forget. The member removal is still important it cleans up the audit trail and signals a clean handoff.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resource-level access: deployments and projects
&lt;/h2&gt;

&lt;p&gt;Roles apply at the organization level by default. But NEXUS AI also supports &lt;strong&gt;project-scoped membership&lt;/strong&gt; isolating access to a subset of deployments within an organization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add a Developer to a specific project only&lt;/span&gt;
nexus project member add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; payments-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--email&lt;/span&gt; engineer@company.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt; Developer

&lt;span class="c"&gt;# They can now deploy payments-service/* deployments&lt;/span&gt;
&lt;span class="c"&gt;# They cannot see auth-service/*, user-service/*, or any other project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project-scoped access is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regulated workloads&lt;/strong&gt; — your payments team accesses the payments project; your analytics team accesses the analytics project. No overlap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenant organizations&lt;/strong&gt; agencies managing deployments for multiple clients. Each client's project is isolated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contractor access&lt;/strong&gt; — limit a vendor to exactly the project they're working on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Organization-level Admins retain visibility across all projects. Project-scoped Developers cannot see outside their project boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  RBAC and AI agents
&lt;/h2&gt;

&lt;p&gt;NEXUS AI's 37 MCP tools for Claude and AI agents operate under the same RBAC model as human callers. A token issued to an AI agent carries exactly the same scope enforcement no exceptions.&lt;/p&gt;

&lt;p&gt;This matters because AI agents tend to be given more access than they need "because it's easier." An agent with &lt;code&gt;admin&lt;/code&gt; scope that goes wrong is a full organization compromise. An agent with &lt;code&gt;deploy:read&lt;/code&gt; that goes wrong reveals status information and nothing else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Designing safe agent access
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Read-only diagnostic agent&lt;/strong&gt; — Claude inspects logs, checks deployment health, surfaces anomalies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"claude-diagnostic"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:read,logs:read &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires&lt;/span&gt; 7d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent cannot deploy, rollback, or change anything. It observes and reports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment automation agent&lt;/strong&gt; — Claude reacts to CI signals and triggers redeployments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"claude-deploy-agent"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:read,deploy:write,logs:read &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires&lt;/span&gt; 30d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent can act on deployments. It cannot touch secrets, billing, or team membership.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incident response agent&lt;/strong&gt; — Claude triages a production incident, can rollback if needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Short-lived, manually issued during an incident&lt;/span&gt;
nexus token create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"claude-incident-2026-04-21"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scopes&lt;/span&gt; deploy:read,deploy:write,logs:read &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires&lt;/span&gt; 4h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4-hour expiry. The token disappears when the incident window ends. No standing elevated access for AI agents.&lt;/p&gt;

&lt;p&gt;The rule: grant an AI agent the minimum scope it needs to complete its defined task. Then set an expiry that matches the task duration — not "never" because that's convenient.&lt;/p&gt;




&lt;h2&gt;
  
  
  What RBAC cannot do
&lt;/h2&gt;

&lt;p&gt;Knowing the limits of any security control is as important as knowing what it covers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RBAC does not protect against a compromised Owner account.&lt;/strong&gt; The Owner role has full access. If an Owner's credentials are compromised, the attacker has full access. Protect Owner accounts with hardware MFA, not just TOTP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RBAC does not prevent a Developer from logging sensitive data.&lt;/strong&gt; If your application logs &lt;code&gt;process.env.DATABASE_URL&lt;/code&gt; at startup, that value appears in runtime logs — which Developers can read. Secret management starts with application code discipline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RBAC does not enforce network-level isolation.&lt;/strong&gt; A Developer with &lt;code&gt;deploy:write&lt;/code&gt; can push a container that opens a reverse shell. Pair RBAC with container security policies and network egress controls for workloads that require it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RBAC does not replace secrets rotation.&lt;/strong&gt; Least privilege reduces blast radius when a secret is compromised. Rotation reduces the window of exposure. Both are required for a complete security posture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The access model audit
&lt;/h2&gt;

&lt;p&gt;Run this quarterly. It takes 20 minutes and it will find something to fix every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List all organization members and their roles&lt;/span&gt;
nexus member list

&lt;span class="c"&gt;# List all active tokens with creation date and last-used date&lt;/span&gt;
nexus token list &lt;span class="nt"&gt;--show-last-used&lt;/span&gt;

&lt;span class="c"&gt;# Check for tokens with no expiry&lt;/span&gt;
nexus token list &lt;span class="nt"&gt;--no-expiry&lt;/span&gt;

&lt;span class="c"&gt;# Check for tokens unused in 30+ days&lt;/span&gt;
nexus token list &lt;span class="nt"&gt;--unused-since&lt;/span&gt; 30d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each token unused in 30+ days: revoke it. For each &lt;code&gt;admin&lt;/code&gt;-scoped token that isn't for a one-time script: replace it with narrower scopes. For each member at a role higher than their current responsibilities: downgrade it.&lt;/p&gt;

&lt;p&gt;The goal is to reach a state where every active token has a name that explains exactly what it does, an expiry that matches how long it needs to exist, and the minimum scope to do its job.&lt;/p&gt;




&lt;h2&gt;
  
  
  RBAC and compliance
&lt;/h2&gt;

&lt;p&gt;If you're in a regulated industry healthcare, fintech, legal — RBAC is table stakes for compliance. NEXUS AI's RBAC system maps directly to common control requirements:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Compliance requirement&lt;/th&gt;
&lt;th&gt;NEXUS AI control&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Least-privilege access&lt;/td&gt;
&lt;td&gt;Role hierarchy + token scopes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Separation of duties&lt;/td&gt;
&lt;td&gt;Developers cannot write secrets; Owners are unique&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access review&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;nexus member list&lt;/code&gt;, &lt;code&gt;nexus token list&lt;/code&gt; for quarterly audits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privileged access management&lt;/td&gt;
&lt;td&gt;Admin and Owner roles with MFA enforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access revocation on termination&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;nexus member remove&lt;/code&gt; + &lt;code&gt;nexus token revoke&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit trail&lt;/td&gt;
&lt;td&gt;Append-only audit logs with actor, token ID, timestamp, and IP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Enterprise and Enterprise On-Prem plans include 90-day and indefinite audit log retention respectively. Logs are exportable to Datadog, Grafana, Splunk, or any SIEM via the audit log export API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist: production-grade RBAC setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Assign roles at the minimum level needed start with Developer, escalate to Admin only when demonstrated necessary&lt;/li&gt;
&lt;li&gt;[ ] No team member should have Owner role unless they're accountable for the organization&lt;/li&gt;
&lt;li&gt;[ ] Every CI/CD pipeline uses a separate &lt;code&gt;deploy:write&lt;/code&gt; token per environment&lt;/li&gt;
&lt;li&gt;[ ] Every token has a name that identifies its purpose and a &lt;code&gt;--expires&lt;/code&gt; flag&lt;/li&gt;
&lt;li&gt;[ ] No &lt;code&gt;admin&lt;/code&gt;-scoped tokens in standing use only for one-time scripts with 1-day expiry&lt;/li&gt;
&lt;li&gt;[ ] AI agent tokens scoped to exactly what the agent does (not &lt;code&gt;admin&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Quarterly access review: &lt;code&gt;nexus token list --unused-since 30d&lt;/code&gt; and &lt;code&gt;nexus member list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Project-scoped membership for workloads that should be isolated (payments, healthcare, multi-client)&lt;/li&gt;
&lt;li&gt;[ ] Owner account protected with hardware MFA (YubiKey or equivalent)&lt;/li&gt;
&lt;li&gt;[ ] Offboarding runbook: member remove + all associated tokens revoke, same day&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can a Developer see their own Access Tokens after creation?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Token values are shown once at creation — never again. A Developer can list their tokens by name and ID (&lt;code&gt;nexus token list --mine&lt;/code&gt;), but the &lt;code&gt;token_value&lt;/code&gt; is never retrievable. If lost, rotate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens to tokens when a member is removed?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Tokens are scoped to the organization, not to the member who created them. Removing a member does not automatically revoke their tokens. Run &lt;code&gt;nexus token list --created-by email@company.com&lt;/code&gt; and revoke manually as part of offboarding. A future release will offer member-removal with automatic token revocation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can a Developer escalate their own role?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Role changes require Admin or Owner. A Developer cannot call any API endpoint that modifies their own or another member's role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does NEXUS AI handle role changes mid-session?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Role and scope changes take effect immediately. An active API session using a token that gets revoked will receive a &lt;code&gt;401 Unauthorized&lt;/code&gt; on the next call — there's no grace window for human sessions (only for the 5-minute deploy token rotation window).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a way to grant time-limited elevated access without creating a token?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not currently at the role level — role changes are persistent until manually reverted. Use a short-lived &lt;code&gt;admin&lt;/code&gt;-scoped token for temporary elevated operations instead of upgrading a member's role. This keeps the audit trail cleaner and eliminates the "I forgot to downgrade them" failure mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We're on the Starter plan. Do we get RBAC?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. All four roles and the full scope system ship on every plan, including Starter at $29/mo. Project-scoped membership and audit log export are Enterprise features.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Access control works best when it's boring when every token has a clear purpose, every role is appropriate, and your quarterly audit finds nothing to clean up. That state is achievable. It requires an initial setup investment of about two hours and 20 minutes of discipline every quarter.&lt;/p&gt;

&lt;p&gt;Start with your CI/CD tokens. Replace any &lt;code&gt;admin&lt;/code&gt;-scoped pipeline token with &lt;code&gt;deploy:write&lt;/code&gt;. That one change eliminates your largest standing access risk.&lt;/p&gt;

&lt;p&gt;For regulated workloads, compliance tooling, or teams larger than 20 engineers, the Enterprise plan adds SAML SSO, custom audit log retention, and dedicated security review. Reach out at &lt;a href="https://nexusai.run" rel="noopener noreferrer"&gt;nexusai.run&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop shipping secrets. Start using a vault.&lt;/li&gt;
&lt;li&gt;MCP integration: 37 tools for Claude and AI agents&lt;/li&gt;
&lt;li&gt;Audit logs and compliance: what gets recorded and why&lt;/li&gt;
&lt;li&gt;How NEXUS AI deploys your app in under 5 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Least privilege is not paranoia. It's the discipline that makes incidents containable.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>rbac</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>NEXUS AI One-Prompt Deployment Is Here Just Describe It and Ship It</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:37:32 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-one-prompt-deployment-is-here-just-describe-it-and-ship-it-17op</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-one-prompt-deployment-is-here-just-describe-it-and-ship-it-17op</guid>
      <description>&lt;h1&gt;
  
  
  One Prompt Deployment Is Here Just Describe It and Ship It
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Tell it what you want. Watch it deploy.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Headline Options
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;One-Prompt Deployment Is Here Just Describe It and Ship It&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy With Words: Introducing One-Prompt Deployment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forget the Config — Just Tell It What to Deploy&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's a version of deployment that feels like magic. You describe what you want — in plain English, in a single line — and your app is live. No YAML. No CLI flags. No digging through docs to remember what &lt;code&gt;--replicas&lt;/code&gt; does in this context.&lt;/p&gt;

&lt;p&gt;That version of deployment exists now. Meet &lt;strong&gt;One-Prompt Deployment&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is One-Prompt Deployment?
&lt;/h2&gt;

&lt;p&gt;One-Prompt Deployment lets you trigger and configure deployments using natural language. Instead of writing pipeline configs or remembering command syntax, you just describe your intent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Deploy the latest build of the payments service to staging with 3 replicas and a 5-minute timeout."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. The system interprets your intent, maps it to the right configuration, runs pre-flight checks, and ships it all without you touching a config file or terminal command.&lt;/p&gt;

&lt;p&gt;It's not a chatbot wrapped around a deploy button. Under the hood, it's a structured inference layer that translates natural language into validated deployment operations, with full auditability and rollback built in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Built This
&lt;/h2&gt;

&lt;p&gt;Deployment tooling has gotten incredibly powerful over the last decade but with that power came complexity. Kubernetes configs, Helm charts, custom CI/CD pipelines: each layer adds capability, but also adds surface area to learn, maintain, and debug.&lt;/p&gt;

&lt;p&gt;We wanted to give developers the full power of that tooling without requiring them to become experts in every layer of it. One-Prompt Deployment is the result: a natural language interface that sits on top of your existing infrastructure and makes it approachable for everyone on the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes It Different
&lt;/h2&gt;

&lt;h3&gt;
  
  
  It Moves at the Speed of Thought
&lt;/h3&gt;

&lt;p&gt;The fastest interface is the one where you don't have to translate your intent into syntax. With One-Prompt Deployment, you describe what you want in natural language and the system handles the translation. In practice, this means going from "I want to deploy this" to "it's deployed" in under two minutes including the time it takes to type the prompt.&lt;/p&gt;

&lt;p&gt;No more context-switching to look up CLI flags or YAML schema. No more copy-pasting config from a deployment that worked last time. Just describe it and ship it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Works With Your Stack, Out of the Box
&lt;/h3&gt;

&lt;p&gt;One-Prompt Deployment understands the vocabulary of your existing infrastructure. Connect it to your cloud provider, container registry, and environment configs, and it immediately knows the names of your services, your environment tiers, and your deployment conventions.&lt;/p&gt;

&lt;p&gt;That means your prompts can be natural and specific: &lt;em&gt;"Roll out the new auth service to production using the blue/green strategy"&lt;/em&gt; — and it knows exactly what "auth service," "production," and "blue/green" mean in your context. No training required, no custom setup beyond your existing connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guardrails Built In — Not Bolted On
&lt;/h3&gt;

&lt;p&gt;Natural language is flexible, which means there's room for ambiguity. We take that seriously. Before any deployment runs, the system surfaces a confirmation summary showing exactly what it understood and what it's about to do. You review, approve, and then it executes.&lt;/p&gt;

&lt;p&gt;If something looks off at the pre-flight stage, it halts and explains why — with a suggested fix in plain language. And if a deployment does go wrong post-launch, automatic rollback restores your last stable state, no incident bridge required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unlocks Deployment for Your Whole Team
&lt;/h3&gt;

&lt;p&gt;This is the one we're most excited about. Traditionally, production deployments are gatekept not because teams &lt;em&gt;want&lt;/em&gt; them to be, but because the tooling is too complex for anyone outside of platform or DevOps to use safely.&lt;/p&gt;

&lt;p&gt;One-Prompt Deployment changes that calculus. QA engineers can deploy to staging environments without waiting on a pipeline engineer. Product managers can trigger approved releases without opening a terminal. On-call rotations can use it to execute rollbacks without institutional knowledge of your infra.&lt;/p&gt;

&lt;p&gt;Your deployment process doesn't have to be a bottleneck anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Enabling One-Prompt Deployment takes about five minutes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Settings → Deployments → Prompt Mode&lt;/strong&gt; in your dashboard&lt;/li&gt;
&lt;li&gt;Connect your infrastructure integrations (cloud provider, registry, environments)&lt;/li&gt;
&lt;li&gt;Run a test prompt to confirm your context is loaded correctly&lt;/li&gt;
&lt;li&gt;Start deploying&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Full documentation including prompt syntax tips, advanced configuration, and the API reference for programmatic prompt-triggered deployments is in our developer docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Coming Next
&lt;/h2&gt;

&lt;p&gt;We're already building on this foundation. Next up: prompt-based deployment schedules (&lt;em&gt;"deploy every Friday at 5pm if all tests pass"&lt;/em&gt;), multi-service orchestration prompts, and a prompt history log with diff views so you can audit exactly what was deployed and when.&lt;/p&gt;

&lt;p&gt;We'd love your feedback as you use it. Join the conversation in our community Discord, open a GitHub Discussion, or just reply to this post. The best features we've built have come directly from developers telling us what's broken or missing — and this one is no different.&lt;/p&gt;

&lt;p&gt;Ship the thing. We've handled the rest. 🚀&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; [NEXUS AI Team]&lt;br&gt;
&lt;strong&gt;Published:&lt;/strong&gt; [8/15/2026]&lt;br&gt;
&lt;strong&gt;Tags:&lt;/strong&gt; deployments, developer tools, AI, natural language, CI/CD, new feature, engineering&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>app</category>
      <category>automation</category>
    </item>
    <item>
      <title>Getting Started: NEXUS AI Connector on Claude</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:30:38 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/getting-started-nexus-ai-connector-on-claude-1dh4</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/getting-started-nexus-ai-connector-on-claude-1dh4</guid>
      <description>&lt;h1&gt;
  
  
  Getting Started: NEXUS AI Connector on Claude
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Your entire deployment platform, accessible through a single conversation.
&lt;/h2&gt;




&lt;h3&gt;
  
  
  Headline Options
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Getting Started: NEXUS AI Connector on Claude&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control NEXUS AI With Claude — No Dashboard Required&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meet the NEXUS AI Connector: Deploy, Monitor, and Manage With Just a Prompt&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;What if you could deploy an app, check its health, spin up a database, and rotate a secret — all without leaving your AI assistant? No tab-switching, no dashboard hunting, no copy-pasting deployment IDs.&lt;/p&gt;

&lt;p&gt;That's exactly what the &lt;strong&gt;NEXUS AI Connector for Claude&lt;/strong&gt; makes possible. It connects your NEXUS AI account directly to Claude, giving you full control of your infrastructure through natural language. This guide walks you through getting set up and making your first prompt-driven deployment in under ten minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the NEXUS AI Connector?
&lt;/h2&gt;

&lt;p&gt;The NEXUS AI Connector is an MCP (Model Context Protocol) integration that exposes your NEXUS AI platform — deployments, databases, secrets, domains, and more — as tools Claude can use on your behalf.&lt;/p&gt;

&lt;p&gt;Once connected, Claude isn't just answering questions about your infrastructure. It's actually interacting with it: listing your running deployments, reading logs, scaling services, and executing the same operations you'd normally do through the dashboard or CLI.&lt;/p&gt;

&lt;p&gt;Think of it as a natural language interface sitting on top of everything NEXUS AI can do.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Can Do With It
&lt;/h2&gt;

&lt;p&gt;Here's a quick taste of what you can ask Claude once the connector is set up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"List all my running deployments"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Deploy the latest build of my API service to staging"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Show me the last 50 runtime logs for the payments service"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Create a new secret called DATABASE_URL for the production environment"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Add a custom domain to my frontend deployment"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Scale my backend service to 3 replicas"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"What's the health status of my production deployments?"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No syntax to memorize. No CLI to install. Just describe what you need.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started in 3 Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Connect Your NEXUS AI Account
&lt;/h3&gt;

&lt;p&gt;Open Claude and navigate to &lt;strong&gt;Settings → Connectors&lt;/strong&gt;. Find the NEXUS AI Connector in the list and click &lt;strong&gt;Connect&lt;/strong&gt;. You'll be prompted to authenticate with your NEXUS AI credentials — this uses a secure OAuth flow, so your credentials are never stored in the conversation.&lt;/p&gt;

&lt;p&gt;Once authenticated, Claude will confirm that your account is linked and show you a summary of the resources it can access.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you're on a Team or Enterprise plan, check with your org admin to make sure the NEXUS AI Connector is enabled in your workspace settings.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Step 2: Verify the Connection
&lt;/h3&gt;

&lt;p&gt;Ask Claude something simple to confirm everything is working:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What deployments do I have running right now?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude will call the NEXUS AI API and return a list of your active deployments — names, statuses, providers, and environments. If you see your infrastructure listed back at you, you're good to go.&lt;/p&gt;

&lt;p&gt;If Claude says it can't find any deployments, double-check that you connected the right NEXUS AI account and that your deployments are in a &lt;code&gt;running&lt;/code&gt; or &lt;code&gt;deploying&lt;/code&gt; state.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Try Your First Prompt-Driven Action
&lt;/h3&gt;

&lt;p&gt;Now for the fun part. Try a real operation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Deploy nginx:latest to port 80 in my development environment."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude will use the NEXUS AI Connector to kick off the deployment, then confirm what it's doing before executing. Once it's underway, you can follow up:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What's the status of that deployment?"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"Show me the build logs."&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"Is it healthy yet?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude handles the back-and-forth with the API so you can stay in the conversation flow instead of jumping to the dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Few Things Worth Knowing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Actions that modify your infrastructure require confirmation.&lt;/strong&gt; Before Claude executes anything that changes state — deploys, scales, deletes, or modifies secrets — it will summarize what it's about to do and ask you to confirm. This is intentional. You stay in control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sensitive values are protected.&lt;/strong&gt; When you ask Claude to create or update secrets, it will execute the operation but will never display secret values in the conversation. What goes into NEXUS AI stays in NEXUS AI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your logs and metrics are available inline.&lt;/strong&gt; Ask Claude to pull logs mid-conversation and it will surface them directly — no need to open a separate terminal or dashboard tab. You can filter by log type, limit line counts, or ask Claude to highlight errors for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Everything is auditable.&lt;/strong&gt; Every operation Claude performs via the connector maps to a real NEXUS AI API call. Your audit trail in NEXUS AI reflects all activity, whether it was initiated through the dashboard, CLI, or Claude.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Possible When You Put It Together
&lt;/h2&gt;

&lt;p&gt;Once you're comfortable with the basics, the connector really shines in more complex workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debug faster:&lt;/strong&gt; Ask Claude to pull logs, identify errors, propose a fix, and redeploy — all in a single conversation thread&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incident response:&lt;/strong&gt; In a live incident, describe the symptoms and ask Claude to check deployment health, pull recent logs, and execute a rollback if needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Onboarding:&lt;/strong&gt; New engineers can interact with production-adjacent environments without needing to learn every CLI tool in your stack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routine ops:&lt;/strong&gt; Automate repetitive deployment checks or environment refreshes by describing what you need rather than scripting it&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Ready to Try It?
&lt;/h2&gt;

&lt;p&gt;The NEXUS AI Connector is available now. Head to your Claude settings, connect your account, and start your first session. The full list of supported operations — deployments, databases, secrets, domains, logs, health checks, and more — is documented in our connector reference docs.&lt;/p&gt;

&lt;p&gt;If you run into anything unexpected, drop a message in our community Discord or open a support ticket directly from your NEXUS AI dashboard.&lt;/p&gt;

&lt;p&gt;Your infrastructure is one prompt away. 🚀&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; [Saif Ali]&lt;br&gt;
&lt;strong&gt;Published:&lt;/strong&gt; [4/20/2026]&lt;br&gt;
&lt;strong&gt;Tags:&lt;/strong&gt; NEXUS AI, Claude, MCP, connector, deployments, developer tools, getting started, AI infrastructure&lt;/p&gt;

</description>
    </item>
    <item>
      <title>NEXUS AI - Claude Code Tutorial</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:30:56 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-claude-code-tutorial-19ml</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-claude-code-tutorial-19ml</guid>
      <description>&lt;p&gt;Most Claude Code tutorials stop at "here's how to install it." That's like teaching someone to drive by showing them the ignition. This Claude Code tutorial goes further — you'll use it to build a real AI-powered app from scratch and deploy it to production, step by step.&lt;/p&gt;

&lt;p&gt;By the end you'll have a working document Q&amp;amp;A API and a live deployment URL. The whole thing takes about an afternoon.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Claude Code actually is (and why it's different)
&lt;/h2&gt;

&lt;p&gt;Claude Code is Anthropic's AI coding agent that runs in your terminal. Unlike copilot-style tools that suggest individual lines inside an editor, Claude Code operates at the project level — it reads your entire codebase, understands how files relate to each other, and makes multi-file changes with full context.&lt;/p&gt;

&lt;p&gt;The practical difference: you describe what you want to build, and Claude Code writes the code, runs commands, fixes errors, and iterates — without you switching between a chat window and your editor. It's AI-augmented development where the AI is a collaborator in your actual workflow, not a suggestion box beside it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes it powerful for AI app development specifically:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can generate boilerplate for FastAPI, Express, or any framework in seconds&lt;/li&gt;
&lt;li&gt;It writes tests alongside the code it generates&lt;/li&gt;
&lt;li&gt;It catches its own mistakes by running the code and reading error output&lt;/li&gt;
&lt;li&gt;It handles the tedious parts (CI config, requirements.txt, test scaffolding) while you focus on the actual problem&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting started: install and configure Claude Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Requires Node.js 18+. Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Authenticate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On first run, Claude Code opens a browser window to authenticate with your Anthropic account. Once authenticated, it drops you into an interactive session in your current directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your first command
&lt;/h3&gt;

&lt;p&gt;Navigate to an empty project folder and try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-ai-app &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;my-ai-app
claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Claude Code prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Scaffold a FastAPI project with a single /health endpoint, a requirements.txt, and a .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code will create the files, show you what it's doing, and confirm. This is the core interaction pattern: describe the outcome, let it execute.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build a real AI app with Claude Code
&lt;/h2&gt;

&lt;p&gt;We're building a &lt;strong&gt;document Q&amp;amp;A API&lt;/strong&gt; — you upload a text document, ask questions about it, and get answers grounded in the document's content. It's a practical RAG (retrieval-augmented generation) pattern used in real products.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Scaffold the project
&lt;/h3&gt;

&lt;p&gt;In your Claude Code session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Create a FastAPI app for document Q&amp;amp;A. The app should:
&amp;gt; - Accept a POST /upload endpoint that takes a text file and stores it in memory
&amp;gt; - Accept a POST /ask endpoint that takes a document_id and a question, then answers using OpenAI gpt-4o-mini
&amp;gt; - Return answers in JSON with the answer text and a confidence field
&amp;gt; - Include a requirements.txt with fastapi, uvicorn, openai, and python-multipart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code will generate the full project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-ai-app/
├── main.py
├── requirements.txt
├── .gitignore
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It writes the entire &lt;code&gt;main.py&lt;/code&gt; — endpoints, in-memory document store, OpenAI call — in one pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Run it and fix errors
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Run the app locally with uvicorn and show me any errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code executes &lt;code&gt;uvicorn main:app --reload&lt;/code&gt;, reads the output, and if there are import errors or missing packages it fixes them automatically. This loop — run, read error, fix — is where Claude Code earns its keep. You don't context-switch; it just handles it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Add real retrieval (not just stuffing the whole document)
&lt;/h3&gt;

&lt;p&gt;The naive version sends the entire document to the model on every question. That breaks on large files and wastes tokens. Ask Claude Code to improve it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; The current /ask endpoint sends the full document to OpenAI on every request.
&amp;gt; Refactor it to:
&amp;gt; - Split documents into 500-token chunks on upload
&amp;gt; - Use cosine similarity on TF-IDF vectors to find the top 3 relevant chunks
&amp;gt; - Only send those 3 chunks to OpenAI as context
&amp;gt; - Use numpy and sklearn for the vector operations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is multi-file, multi-concept work. Claude Code will update &lt;code&gt;main.py&lt;/code&gt;, add &lt;code&gt;sklearn&lt;/code&gt; and &lt;code&gt;numpy&lt;/code&gt; to &lt;code&gt;requirements.txt&lt;/code&gt;, and implement the chunking + retrieval logic coherently. It understands that changing the upload flow affects the query flow and handles both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Write tests
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Write pytest tests for both endpoints. Include:
&amp;gt; - A test that uploads a sample document and verifies the document_id is returned
&amp;gt; - A test that uploads a document, then asks a question whose answer is clearly in the document
&amp;gt; - A test that asks about a document_id that doesn't exist and expects a 404
&amp;gt; Mock the OpenAI call so tests don't need a real API key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code generates &lt;code&gt;test_main.py&lt;/code&gt; with the exact structure you described, uses &lt;code&gt;pytest-mock&lt;/code&gt; for the OpenAI mock, and adds the test dependencies to &lt;code&gt;requirements.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Run the tests and fix any failures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code runs &lt;code&gt;pytest&lt;/code&gt;, reads the output, and iterates until they pass. The critical detail: it doesn't just generate tests and hand them back — it runs them and closes the feedback loop.&lt;/p&gt;




&lt;h2&gt;
  
  
  The CLAUDE.md file: your project's AI instruction layer
&lt;/h2&gt;

&lt;p&gt;One of the most underused Claude Code features is &lt;code&gt;CLAUDE.md&lt;/code&gt; — a file in your project root that Claude Code reads at the start of every session. Think of it as a permanent briefing document for your AI collaborator.&lt;/p&gt;

&lt;p&gt;Create one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Create a CLAUDE.md for this project that documents:
&amp;gt; - The tech stack (FastAPI, OpenAI, sklearn)
&amp;gt; - The coding conventions we used (snake_case, type hints everywhere, docstrings on public functions)
&amp;gt; - The test setup (pytest, mock OpenAI calls)
&amp;gt; - What the /upload and /ask endpoints do
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this point on, any new Claude Code session on this project starts with full context. You don't re-explain the stack every time.&lt;/p&gt;

&lt;p&gt;A good &lt;code&gt;CLAUDE.md&lt;/code&gt; includes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project: Document Q&amp;amp;A API&lt;/span&gt;

&lt;span class="gu"&gt;## Stack&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; FastAPI + Uvicorn (Python 3.11)
&lt;span class="p"&gt;-&lt;/span&gt; OpenAI gpt-4o-mini for generation
&lt;span class="p"&gt;-&lt;/span&gt; sklearn TF-IDF + cosine similarity for retrieval
&lt;span class="p"&gt;-&lt;/span&gt; pytest + pytest-mock for testing

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Type hints on all function signatures
&lt;span class="p"&gt;-&lt;/span&gt; Snake_case everywhere
&lt;span class="p"&gt;-&lt;/span&gt; Docstrings on all public functions

&lt;span class="gu"&gt;## Architecture&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Documents stored in-memory (dict keyed by UUID)
&lt;span class="p"&gt;-&lt;/span&gt; Chunks: 500 tokens, 50-token overlap
&lt;span class="p"&gt;-&lt;/span&gt; Top 3 chunks retrieved per query

&lt;span class="gu"&gt;## Running locally&lt;/span&gt;
uvicorn main:app --reload --port 8000

&lt;span class="gu"&gt;## Running tests&lt;/span&gt;
pytest -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploy to production with the NEXUS AI CLI
&lt;/h2&gt;

&lt;p&gt;Your app is built and tested. Now get it live — no Dockerfile required.&lt;/p&gt;

&lt;p&gt;NEXUS AI detects your framework, builds the container for you, and deploys it. You push source code; NEXUS AI handles everything from there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 — Push source to GitHub
&lt;/h3&gt;

&lt;p&gt;Initialize a repo and push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"initial: document Q&amp;amp;A API"&lt;/span&gt;
gh repo create my-ai-app &lt;span class="nt"&gt;--public&lt;/span&gt; &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or push to an existing repo. The only requirement is that your &lt;code&gt;requirements.txt&lt;/code&gt; is at the project root — NEXUS AI uses it to detect that this is a Python app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6 — Install the NEXUS AI CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://nexusai.run/install.sh | bash

&lt;span class="c"&gt;# macOS&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://nexusai.run/install-mac.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7 — Deploy from source
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Log in to NEXUS AI&lt;/span&gt;
nexus auth login

&lt;span class="c"&gt;# Deploy directly from your GitHub repo — no Docker required&lt;/span&gt;
nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your-org/my-ai-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; doc-qa-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 8000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; gcp_cloud_run

&lt;span class="c"&gt;# Add the OpenAI key as an encrypted secret&lt;/span&gt;
nexus secret create OPENAI_API_KEY &lt;span class="nt"&gt;--deployment&lt;/span&gt; doc-qa-api

&lt;span class="c"&gt;# Attach a custom domain&lt;/span&gt;
nexus domain add api.yourcompany.com &lt;span class="nt"&gt;--deployment&lt;/span&gt; doc-qa-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEXUS AI clones your repo, detects the Python/FastAPI framework, builds a production container image, and deploys it. Within 2–3 minutes you have a live URL with TLS and autoscaling. Stream logs to verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy logs doc-qa-api &lt;span class="nt"&gt;--follow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automate deploys with GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Ask Claude Code to write the CI/CD config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;Write&lt;/span&gt; &lt;span class="err"&gt;a&lt;/span&gt; &lt;span class="err"&gt;GitHub&lt;/span&gt; &lt;span class="err"&gt;Actions&lt;/span&gt; &lt;span class="err"&gt;workflow&lt;/span&gt; &lt;span class="err"&gt;that&lt;/span&gt; &lt;span class="err"&gt;redeploys&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;NEXUS&lt;/span&gt; &lt;span class="err"&gt;AI&lt;/span&gt; &lt;span class="err"&gt;deployment&lt;/span&gt; &lt;span class="err"&gt;on&lt;/span&gt; &lt;span class="err"&gt;every&lt;/span&gt; &lt;span class="err"&gt;push&lt;/span&gt; &lt;span class="err"&gt;to&lt;/span&gt; &lt;span class="err"&gt;main.&lt;/span&gt;
&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s"&gt; Use NEXUSAI_TOKEN as a secret. The deployment name is doc-qa-api.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code generates a complete &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;. The workflow calls &lt;code&gt;nexus deploy redeploy doc-qa-api&lt;/code&gt; — NEXUS AI pulls the latest source, rebuilds the container, and rolls it out. Every push to &lt;code&gt;main&lt;/code&gt; goes to production automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Advanced Claude Code patterns for AI development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multi-file refactoring
&lt;/h3&gt;

&lt;p&gt;Claude Code handles refactors that would take hours manually. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; The document store is currently an in-memory dict. Refactor it to use Redis so documents
&amp;gt; persist across server restarts. Update all references, add redis to requirements.txt,
&amp;gt; and update the CLAUDE.md architecture section.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It updates &lt;code&gt;main.py&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;, and &lt;code&gt;CLAUDE.md&lt;/code&gt; in one coherent pass — and since NEXUS AI builds from source, you just push the changes and redeploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging without context-switching
&lt;/h3&gt;

&lt;p&gt;When something breaks in production:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy logs doc-qa-api &lt;span class="nt"&gt;--tail&lt;/span&gt; 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the error, paste it into Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Getting this error in production logs: [paste error]
&amp;gt; Find the root cause and fix it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code reads the relevant code, identifies the issue, and applies the fix — all without you manually tracing through stack traces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Claude Code for code review
&lt;/h3&gt;

&lt;p&gt;Before opening a PR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;&amp;gt; Review the changes in git diff HEAD~1 for:
&amp;gt; - Security issues (injection, hardcoded secrets, unsafe deserialization)
&amp;gt; - Missing input validation on the API endpoints
&amp;gt; - Performance issues in the chunking logic
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code runs the diff and produces a structured review with specific line references.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Claude Code mistakes to avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Giving vague prompts.&lt;/strong&gt; "Make this better" produces mediocre output. "Refactor the chunking function to reduce memory allocation by processing tokens in a streaming fashion instead of loading the full document" produces a specific, actionable change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not using CLAUDE.md.&lt;/strong&gt; Without it, you re-explain your stack every session. Ten minutes setting it up saves hours over the life of a project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accepting the first output blindly.&lt;/strong&gt; Claude Code is fast, not infallible. Run the tests after every significant change. When they fail, let Claude Code fix them — that feedback loop is what makes it reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Letting it over-engineer.&lt;/strong&gt; Claude Code will sometimes propose abstractions you don't need. If you asked for a simple endpoint and got a three-layer architecture with an abstract repository pattern, push back: "Simplify this — no abstraction layers, just the endpoint and direct database calls."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not scoping the context.&lt;/strong&gt; In very large codebases, &lt;code&gt;claude&lt;/code&gt; in the root directory gives it the whole repo. For a focused change, navigate to the relevant subdirectory first. Smaller context = more precise output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Claude Code work with languages other than Python?
&lt;/h3&gt;

&lt;p&gt;Yes. Claude Code works with any language — TypeScript, Go, Rust, Ruby, Java. The same patterns apply: scaffold with a prompt, run it, let Claude Code fix errors. The &lt;code&gt;CLAUDE.md&lt;/code&gt; approach works especially well in polyglot repos where you need to document which parts use which language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Claude Code safe to run on production codebases?
&lt;/h3&gt;

&lt;p&gt;Claude Code asks for confirmation before writing files or running commands. You control what it executes. For sensitive production repos, review the proposed changes before confirming — Claude Code shows you a diff before applying it. Never give it credentials directly; use environment variables and secrets managers.&lt;/p&gt;

&lt;h3&gt;
  
  
  How is Claude Code different from GitHub Copilot?
&lt;/h3&gt;

&lt;p&gt;Copilot autocompletes individual lines and functions inside an editor. Claude Code operates at the project level in the terminal — it understands the full codebase, can run code, read test output, and make coordinated multi-file changes. They're complementary: Copilot for keystroke-level suggestions, Claude Code for larger tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Claude Code without an Anthropic account?
&lt;/h3&gt;

&lt;p&gt;No. Claude Code requires an Anthropic API key or Claude.ai Pro/Max subscription. Usage via the API is billed based on token consumption. The claude.ai subscription tiers include a monthly usage allocation.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the best way to handle large codebases?
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;.claudeignore&lt;/code&gt; (same syntax as &lt;code&gt;.gitignore&lt;/code&gt;) to exclude directories that aren't relevant to your current task — &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;venv&lt;/code&gt;, build artifacts. This keeps Claude Code's context focused on what matters and reduces token usage.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you built
&lt;/h2&gt;

&lt;p&gt;Start to finish: a document Q&amp;amp;A API scaffolded by Claude Code, with chunked retrieval, pytest coverage, and a live deployment on NEXUS AI — all without writing a Dockerfile or touching a browser.&lt;/p&gt;

&lt;p&gt;That's AI-augmented development in practice. Claude Code handled the scaffolding, boilerplate, tests, and debugging loop. You handled the architecture decisions and product requirements. The result ships faster and has better test coverage than the same work done manually.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://dev.to/docs"&gt;NEXUS AI CLI&lt;/a&gt; handles the deployment side of this workflow. Install it, run &lt;code&gt;nexus auth login&lt;/code&gt;, and your next Claude Code-built app is one command away from production.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>nexusai</category>
      <category>ai</category>
      <category>web</category>
    </item>
    <item>
      <title>NEXUS AI Audit</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:29:25 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-audit-491g</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-audit-491g</guid>
      <description>&lt;h1&gt;
  
  
  Audit logs and compliance: what gets recorded and why
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Published:&lt;/strong&gt; April 21, 2026&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Security · Compliance&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Reading time:&lt;/strong&gt; 15 minutes&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; NEXUS AI Team&lt;/p&gt;



&lt;p&gt;A production incident happens at 2:47 AM. You wake up to alerts. By the time you open your laptop, the question isn't "what failed" — your monitoring already told you that. The question is "who changed what, when, and from where?"&lt;/p&gt;

&lt;p&gt;Without audit logs, that question takes hours. With audit logs, it takes minutes.&lt;/p&gt;

&lt;p&gt;NEXUS AI records 42 distinct event types across 7 categories — every authentication attempt, every secret operation, every deployment action, every permission change. This post covers exactly what gets recorded, what each severity level means, how retention works, and how the audit log maps to the compliance controls your team, auditors, and regulators care about.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why audit logs exist — and why most teams underinvest in them
&lt;/h2&gt;

&lt;p&gt;Audit logs are not a debugging tool. They are an accountability system.&lt;/p&gt;

&lt;p&gt;The difference matters. A debugging tool helps you understand why software broke. An accountability system answers a harder set of questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did an authorized person take this action?&lt;/li&gt;
&lt;li&gt;From a recognized location?&lt;/li&gt;
&lt;li&gt;At a time that makes sense?&lt;/li&gt;
&lt;li&gt;On the resource they were supposed to touch?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the questions a security incident forces you to answer — and the questions compliance auditors ask during a review. Every minute you spend reconstructing context from application logs and git history is a minute your accountability system didn't pay for itself.&lt;/p&gt;

&lt;p&gt;NEXUS AI's audit log is designed to answer accountability questions in seconds, not hours.&lt;/p&gt;


&lt;h2&gt;
  
  
  The event catalog: 42 event types, 7 categories
&lt;/h2&gt;

&lt;p&gt;Every event stored in the audit log has a named type. Here is the complete catalog.&lt;/p&gt;
&lt;h3&gt;
  
  
  Authentication events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LOGIN_SUCCESS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Successful sign-in via password or OAuth&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LOGIN_FAILED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Failed sign-in attempt (wrong password, invalid token)&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LOGOUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Explicit sign-out&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REGISTER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;New account created&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TOKEN_REFRESH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Session token refreshed&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TOKEN_EXPIRED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Session token expired and was rejected&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Authentication events are the first line of accountability. A single &lt;code&gt;LOGIN_FAILED&lt;/code&gt; is noise. Fifteen &lt;code&gt;LOGIN_FAILED&lt;/code&gt; events from the same IP in 90 seconds is a brute-force signal — recorded, flagged, and available for your SIEM in real time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deployment events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEPLOYMENT_CREATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;New deployment provisioned&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEPLOYMENT_UPDATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deployment configuration changed&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEPLOYMENT_STARTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stopped deployment brought back online&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEPLOYMENT_STOPPED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Running deployment halted&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEPLOYMENT_DELETED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deployment permanently removed&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEPLOYMENT_FAILED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build or container start failed&lt;/td&gt;
&lt;td&gt;ERROR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEPLOYMENT_SCALED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replica count changed&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every deploy action is tied to the actor who triggered it — a user email, a token ID, or both. When a deploy fires at 3 AM, you know whether it was a CI token, a scheduled job, or a human who shouldn't have been working at 3 AM.&lt;/p&gt;
&lt;h3&gt;
  
  
  Security events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DOCKERFILE_VALIDATION_FAILED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Submitted Dockerfile failed safety checks&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RATE_LIMIT_EXCEEDED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;API caller exceeded request rate limits&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UNAUTHORIZED_ACCESS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request rejected due to insufficient permissions&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SUSPICIOUS_ACTIVITY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Behavioral anomaly detected by the security monitor&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CONTAINER_ESCAPE_ATTEMPT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Container process attempted to break isolation&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;SUSPICIOUS_ACTIVITY&lt;/code&gt; and &lt;code&gt;CONTAINER_ESCAPE_ATTEMPT&lt;/code&gt; are the two events that trigger an immediate alert. They are never demoted to WARNING or lower.&lt;/p&gt;
&lt;h3&gt;
  
  
  Resource events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RESOURCE_LIMIT_EXCEEDED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deployment exceeded its CPU, memory, or storage limit&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HIGH_CPU_USAGE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Container CPU usage crossed threshold&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HIGH_MEMORY_USAGE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Container memory usage crossed threshold&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Resource events are included in the audit log — not just the metrics system — because they tell the story of capacity-related incidents. A deployment that gets quietly OOM-killed at 4 PM on a Tuesday has a paper trail.&lt;/p&gt;
&lt;h3&gt;
  
  
  Administrative events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;USER_CREATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;New team member account created or invited&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;USER_DELETED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Team member removed from the organization&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PERMISSION_CHANGED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Role or scope assignment changed&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CONFIG_CHANGED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Organization-level configuration updated&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Administrative events answer the access-review question: not just who has access now, but who granted it, when, and to whom. Every &lt;code&gt;PERMISSION_CHANGED&lt;/code&gt; event records the before and after state in the &lt;code&gt;details&lt;/code&gt; JSON field.&lt;/p&gt;
&lt;h3&gt;
  
  
  Project events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PROJECT_CREATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;New project created&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PROJECT_UPDATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Project metadata or settings changed&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PROJECT_DELETED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Project and all its deployments deleted&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Secret and vault events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SECRET_CREATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;New secret stored in the vault&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SECRET_UPDATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secret value changed&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SECRET_ROTATED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secret rotated (new value, same name)&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SECRET_DELETED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secret removed from the vault&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SECRET_REVEALED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secret value decrypted for display&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SECRET_LISTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secret names listed (values not returned)&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SECRET_RUNTIME_ACCESSED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secret decrypted for container injection at deploy time&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;SECRET_REVEALED&lt;/code&gt; is marked WARNING by design. The vault never returns plaintext values through normal operations — if a &lt;code&gt;SECRET_REVEALED&lt;/code&gt; event fires, an admin explicitly requested a value display. That is worth noting.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SECRET_RUNTIME_ACCESSED&lt;/code&gt; records every time a secret is decrypted for injection into a running container. On a high-frequency redeploy environment, this creates a complete timeline of which secrets were active in which container instances.&lt;/p&gt;
&lt;h3&gt;
  
  
  Database intelligence events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What triggered it&lt;/th&gt;
&lt;th&gt;Default severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DATABASE_ACCESSED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;External database connection established&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DATABASE_MODIFIED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Schema change or DDL applied to external database&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DATABASE_QUERY_EXECUTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SQL query executed against an external database source&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;DATABASE_MODIFIED&lt;/code&gt; is promoted to WARNING because schema changes are high-impact and difficult to reverse. Every DDL statement executed through NEXUS AI's Database Intelligence layer — whether applied directly or via a proposed fix — produces a record.&lt;/p&gt;


&lt;h2&gt;
  
  
  The audit log record
&lt;/h2&gt;

&lt;p&gt;Every event writes a single record to the &lt;code&gt;audit_logs&lt;/code&gt; table. Here is what that record looks like in full:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"f3c8a21b-4d9e-4a7f-b6c1-e2d8f0a3b591"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEPLOYMENT_CREATED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"usr_01HX9..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"organizationId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org_01HX9..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ipAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"140.82.114.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userAgent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nexusapp-cli/2.0.0 node/20.11.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resourceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dep_api-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deployment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEPLOYMENT_CREATED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploymentName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ghcr.io/org/api:sha-abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWS_APP_RUNNER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tokenId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tok_01HX9..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"errorMessage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-21T09:17:05.000Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every field is intentional:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Why it exists&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unique record identifier — stable reference for incident tickets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;eventType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Machine-readable event name — filterable, indexable, SIEM-parseable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;severity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;INFO / WARNING / ERROR / CRITICAL — drives alerting and dashboards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;userId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The human actor (null if action was taken by a token with no session)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;organizationId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tenant boundary — logs are always org-scoped; cross-tenant reads are impossible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ipAddress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Source IP of the request — critical for geolocation anomaly detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;userAgent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CLI version, browser, SDK — surfaces automation vs. human access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resourceId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The specific resource acted upon — deployments, secrets, users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resourceType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The category of resource — enables filtering by type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Human-readable description of what happened&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;details&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Freeform JSON — event-specific context (image tag, region, old role, new role)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;success&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whether the action completed successfully&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;errorMessage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If &lt;code&gt;success&lt;/code&gt; is false, why it failed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UTC timestamp of the event — stored with millisecond precision&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;details&lt;/code&gt; field is where event-specific context lives. A &lt;code&gt;PERMISSION_CHANGED&lt;/code&gt; record includes the old role and new role. A &lt;code&gt;SECRET_RUNTIME_ACCESSED&lt;/code&gt; record includes the deployment ID and the name (not value) of the secret. A &lt;code&gt;LOGIN_FAILED&lt;/code&gt; record includes the email attempted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Severity levels
&lt;/h2&gt;

&lt;p&gt;NEXUS AI uses four severity levels. They control how an event is stored, surfaced, and retained.&lt;/p&gt;

&lt;h3&gt;
  
  
  INFO
&lt;/h3&gt;

&lt;p&gt;Normal system operation. Every successful deploy, login, and secret list operation lands here. INFO events are written to the database and available for query, but they do not trigger any alert. They form the baseline — the record of what "normal" looks like.&lt;/p&gt;

&lt;h3&gt;
  
  
  WARNING
&lt;/h3&gt;

&lt;p&gt;Something worth noting. Failed logins, rate limit hits, secret reveal operations, and Dockerfile validation failures are WARNING events. They do not indicate a breach, but they indicate conditions that — in volume or combination — warrant investigation. Five &lt;code&gt;LOGIN_FAILED&lt;/code&gt; events is noise. Fifty in ten minutes is a pattern your SIEM should surface.&lt;/p&gt;

&lt;h3&gt;
  
  
  ERROR
&lt;/h3&gt;

&lt;p&gt;An action failed in a way that requires attention. &lt;code&gt;DEPLOYMENT_FAILED&lt;/code&gt; is an ERROR. These events are logged to the application error stream in addition to the database, so they appear in your observability pipeline immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  CRITICAL
&lt;/h3&gt;

&lt;p&gt;Immediate action required. Only two event types default to CRITICAL: &lt;code&gt;SUSPICIOUS_ACTIVITY&lt;/code&gt; and &lt;code&gt;CONTAINER_ESCAPE_ATTEMPT&lt;/code&gt;. CRITICAL events trigger the alerting pipeline — currently logging to the critical error stream, with email, Slack, and PagerDuty integrations on the roadmap. CRITICAL events are also exempt from the standard 90-day retention purge. They are kept indefinitely, regardless of plan.&lt;/p&gt;




&lt;h2&gt;
  
  
  The security score
&lt;/h2&gt;

&lt;p&gt;NEXUS AI's security monitor computes a rolling 100-point security score for each organization, recalculated across a configurable window (default: 7 days).&lt;/p&gt;

&lt;p&gt;The score starts at 100 and deducts based on event volume:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event category&lt;/th&gt;
&lt;th&gt;Deduction per occurrence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Failed login (&lt;code&gt;LOGIN_FAILED&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;−2 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limit exceeded (&lt;code&gt;RATE_LIMIT_EXCEEDED&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;−1 point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dockerfile validation failure (&lt;code&gt;DOCKERFILE_VALIDATION_FAILED&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;−5 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Critical security event (&lt;code&gt;severity: CRITICAL&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;−10 points&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A score of 100 means no adverse events in the review window. A score of 60 means something is worth investigating. A score below 40 should trigger an active security review.&lt;/p&gt;

&lt;p&gt;The score is visible in the NEXUS AI dashboard under Settings → Security and is available via the API at &lt;code&gt;GET /api/audit/security-summary&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Retention policy
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Retention window&lt;/th&gt;
&lt;th&gt;CRITICAL event retention&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Starter&lt;/td&gt;
&lt;td&gt;90 days&lt;/td&gt;
&lt;td&gt;Indefinite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;90 days&lt;/td&gt;
&lt;td&gt;Indefinite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise&lt;/td&gt;
&lt;td&gt;Configurable (env: &lt;code&gt;AUDIT_LOG_RETENTION_DAYS&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Indefinite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise On-Prem&lt;/td&gt;
&lt;td&gt;You own the database&lt;/td&gt;
&lt;td&gt;You own the database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The retention job runs daily at 3:30 AM UTC. It purges records older than the retention window — except CRITICAL events, which are never automatically purged.&lt;/p&gt;

&lt;p&gt;On Enterprise, set &lt;code&gt;AUDIT_LOG_RETENTION_DAYS&lt;/code&gt; to any positive integer. Regulated industries typically set this to 365 (HIPAA minimum) or 2555 (7-year financial records requirement).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example: 365-day retention for HIPAA workloads&lt;/span&gt;
&lt;span class="nv"&gt;AUDIT_LOG_RETENTION_DAYS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;365
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Enterprise On-Prem, you bring your own PostgreSQL cluster. Audit logs live in your database, under your retention and backup policies, with no data leaving your infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Accessing your audit logs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dashboard
&lt;/h3&gt;

&lt;p&gt;The audit log viewer is at Settings → Audit Logs in the NEXUS AI dashboard. Filter by event type, severity, date range, and user. Paginated, searchable, exportable.&lt;/p&gt;

&lt;h3&gt;
  
  
  API
&lt;/h3&gt;

&lt;p&gt;The audit log API is at &lt;code&gt;/api/audit/logs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get the last 50 logs&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/logs?limit=50"&lt;/span&gt;

&lt;span class="c"&gt;# Filter by event type&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/logs?eventType=SECRET_UPDATED&amp;amp;limit=100"&lt;/span&gt;

&lt;span class="c"&gt;# Filter by severity&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/logs?severity=WARNING&amp;amp;limit=100"&lt;/span&gt;

&lt;span class="c"&gt;# Date range (ISO 8601)&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/logs?startDate=2026-04-01T00:00:00Z&amp;amp;endDate=2026-04-21T23:59:59Z"&lt;/span&gt;

&lt;span class="c"&gt;# Security summary for the last 7 days&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/security-summary?days=7"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CSV export
&lt;/h3&gt;

&lt;p&gt;Export up to 10,000 log records as a CSV file — ready to upload to your SIEM, compliance platform, or auditor portal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Export last 30 days to CSV&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/export?startDate=2026-03-21T00:00:00Z"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; audit-logs-march-2026.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CSV includes all fields: timestamp, event type, severity, user ID, IP address, action, success, error message, resource ID, and resource type. The &lt;code&gt;details&lt;/code&gt; JSON field is serialized as a string in the CSV export.&lt;/p&gt;

&lt;h3&gt;
  
  
  Available filter endpoints
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/audit/logs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Query logs with filters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/audit/export&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download CSV (up to 10,000 records)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/audit/security-summary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7-day security summary and score&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/audit/security-metrics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Real-time threat metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/audit/event-types&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all 42 event types and 4 severity levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/audit/user-activity/:userId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30-day activity summary for a specific user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Audit logs in a real incident
&lt;/h2&gt;

&lt;p&gt;Here is how audit logs actually look during an incident response workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; At 11:42 PM, a production deployment stops unexpectedly. The on-call engineer opens the audit log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Filter for recent deployment events on the affected resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/logs?eventType=DEPLOYMENT_STOPPED&amp;amp;limit=10"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DEPLOYMENT_STOPPED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tokenId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tok_01HX9..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploymentName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"triggeredBy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"access_token"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ipAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"198.51.100.22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-21T23:42:17.000Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;userId&lt;/code&gt; — the stop was triggered by an Access Token, not a human session. &lt;code&gt;tokenId&lt;/code&gt; identifies which token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Cross-reference the token ID against the token list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus token list &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="s1"&gt;'.[] | select(.id == "tok_01HX9...")'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; The token was named &lt;code&gt;github-actions-prod&lt;/code&gt;. It has &lt;code&gt;deploy:write&lt;/code&gt; scope. But the GitHub Actions workflow that uses it is only supposed to trigger redeployments, not stops.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Pull the full recent activity for that token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/logs?limit=20"&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  jq &lt;span class="s1"&gt;'.data.logs[] | select(.details.tokenId == "tok_01HX9...")'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; The token was used from IP &lt;code&gt;198.51.100.22&lt;/code&gt;. Your CI/CD pipeline runs from &lt;code&gt;140.82.114.0/24&lt;/code&gt;. This IP is outside that range.&lt;/p&gt;

&lt;p&gt;The token was compromised. You revoke it immediately, rotate secrets, and have a complete timeline of every action it took — from the first legitimate use to the unauthorized stop. The entire investigation took 11 minutes.&lt;/p&gt;

&lt;p&gt;Without audit logs: that same investigation would have required GitHub Actions logs, cloud provider logs, and a manual timeline reconstruction. Best case: 90 minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compliance mapping
&lt;/h2&gt;

&lt;p&gt;NEXUS AI's audit log maps directly to the access-control and audit requirements in the major compliance frameworks. This is not a marketing table — these are the specific control IDs your auditor will check.&lt;/p&gt;

&lt;h3&gt;
  
  
  HIPAA
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;HIPAA requirement&lt;/th&gt;
&lt;th&gt;Control ID&lt;/th&gt;
&lt;th&gt;NEXUS AI coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Access control — unique user identification&lt;/td&gt;
&lt;td&gt;§164.312(a)(2)(i)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;userId&lt;/code&gt; on every record; token-based access uses &lt;code&gt;tokenId&lt;/code&gt; in &lt;code&gt;details&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit controls — hardware, software, procedural mechanisms&lt;/td&gt;
&lt;td&gt;§164.312(b)&lt;/td&gt;
&lt;td&gt;42 event types, append-only log, 90–365 day retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automatic logoff — session inactivity termination&lt;/td&gt;
&lt;td&gt;§164.312(a)(2)(iii)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;TOKEN_EXPIRED&lt;/code&gt; event records session termination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption and decryption — PHI protection&lt;/td&gt;
&lt;td&gt;§164.312(a)(2)(iv)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SECRET_RUNTIME_ACCESSED&lt;/code&gt; records every secret decryption event&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Person or entity authentication — verify identity before granting access&lt;/td&gt;
&lt;td&gt;§164.312(d)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LOGIN_FAILED&lt;/code&gt; events surface failed authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  SOC 2 Type II
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SOC 2 criterion&lt;/th&gt;
&lt;th&gt;Trust Service Criterion&lt;/th&gt;
&lt;th&gt;NEXUS AI coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Logical access controls&lt;/td&gt;
&lt;td&gt;CC6.1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PERMISSION_CHANGED&lt;/code&gt;, &lt;code&gt;USER_CREATED&lt;/code&gt;, &lt;code&gt;USER_DELETED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System access authorization&lt;/td&gt;
&lt;td&gt;CC6.2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LOGIN_SUCCESS&lt;/code&gt;, &lt;code&gt;LOGIN_FAILED&lt;/code&gt;, &lt;code&gt;UNAUTHORIZED_ACCESS&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User registration and de-provisioning&lt;/td&gt;
&lt;td&gt;CC6.3&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;USER_CREATED&lt;/code&gt;, &lt;code&gt;USER_DELETED&lt;/code&gt;, &lt;code&gt;PERMISSION_CHANGED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restricting access to data in transit&lt;/td&gt;
&lt;td&gt;CC6.7&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SECRET_RUNTIME_ACCESSED&lt;/code&gt;, &lt;code&gt;DATABASE_ACCESSED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring of system components&lt;/td&gt;
&lt;td&gt;CC7.2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;HIGH_CPU_USAGE&lt;/code&gt;, &lt;code&gt;HIGH_MEMORY_USAGE&lt;/code&gt;, &lt;code&gt;RESOURCE_LIMIT_EXCEEDED&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident detection and reporting&lt;/td&gt;
&lt;td&gt;CC7.3&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SUSPICIOUS_ACTIVITY&lt;/code&gt;, &lt;code&gt;CONTAINER_ESCAPE_ATTEMPT&lt;/code&gt; (CRITICAL, alerted immediately)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  GDPR
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GDPR requirement&lt;/th&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;NEXUS AI coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Records of processing activities&lt;/td&gt;
&lt;td&gt;Art. 30&lt;/td&gt;
&lt;td&gt;Complete event log with timestamp, actor, resource, and outcome&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accountability — demonstrate compliance&lt;/td&gt;
&lt;td&gt;Art. 5(2)&lt;/td&gt;
&lt;td&gt;Append-only log with no modification capability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data access requests — who accessed what&lt;/td&gt;
&lt;td&gt;Art. 15&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;user-activity/:userId&lt;/code&gt; endpoint for per-user activity reports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breach notification — detect and respond within 72 hours&lt;/td&gt;
&lt;td&gt;Art. 33&lt;/td&gt;
&lt;td&gt;CRITICAL events alerted immediately; &lt;code&gt;SUSPICIOUS_ACTIVITY&lt;/code&gt; surfaces breach signals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  PCI DSS (v4.0)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PCI DSS requirement&lt;/th&gt;
&lt;th&gt;Control&lt;/th&gt;
&lt;th&gt;NEXUS AI coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Track and monitor access to cardholder data&lt;/td&gt;
&lt;td&gt;Req. 10.2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;DATABASE_ACCESSED&lt;/code&gt;, &lt;code&gt;DATABASE_QUERY_EXECUTED&lt;/code&gt; for connected payment databases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Record user access to audit trails&lt;/td&gt;
&lt;td&gt;Req. 10.2.1&lt;/td&gt;
&lt;td&gt;All 42 event types record &lt;code&gt;userId&lt;/code&gt; or &lt;code&gt;tokenId&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Record privileged access&lt;/td&gt;
&lt;td&gt;Req. 10.2.1.b&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PERMISSION_CHANGED&lt;/code&gt; records role elevations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retain audit log history for at least 12 months&lt;/td&gt;
&lt;td&gt;Req. 10.7&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;AUDIT_LOG_RETENTION_DAYS=365&lt;/code&gt; on Enterprise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review logs daily&lt;/td&gt;
&lt;td&gt;Req. 10.6&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;GET /api/audit/logs&lt;/code&gt; with date filter; exportable to SIEM&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Integrating with your SIEM
&lt;/h2&gt;

&lt;p&gt;NEXUS AI does not require a native SIEM integration — the export API and JSON query endpoint are designed to plug into any pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Datadog:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Pull last hour of WARNING+ events and ship to Datadog&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://nexusai.run/api/audit/logs?severity=WARNING&amp;amp;startDate=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nt"&gt;-v-1H&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%dT%H:%M:%SZ'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  jq &lt;span class="s1"&gt;'.data.logs[]'&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; event&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://http-intake.logs.datadoghq.com/api/v2/logs"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"DD-API-KEY: &lt;/span&gt;&lt;span class="nv"&gt;$DD_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Grafana / Loki:&lt;/strong&gt; Ship the JSON response from &lt;code&gt;/api/audit/logs&lt;/code&gt; via a log shipper (Promtail, Alloy) configured to poll the endpoint on a scheduled interval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Splunk / SIEM:&lt;/strong&gt; Use the CSV export endpoint (&lt;code&gt;/api/audit/export&lt;/code&gt;) on a scheduled basis and ingest via Splunk's file monitor input.&lt;/p&gt;

&lt;p&gt;On the Enterprise On-Prem plan, audit logs live in your PostgreSQL cluster. Query them directly with any BI or SIEM tool that supports PostgreSQL — no export pipeline required.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the audit log does NOT record
&lt;/h2&gt;

&lt;p&gt;Knowing the boundaries of any control is as important as knowing what it covers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secret values are never logged.&lt;/strong&gt; &lt;code&gt;SECRET_RUNTIME_ACCESSED&lt;/code&gt; records that a secret named &lt;code&gt;DATABASE_URL&lt;/code&gt; was accessed for deployment &lt;code&gt;api-prod&lt;/code&gt;. It does not record the value of &lt;code&gt;DATABASE_URL&lt;/code&gt;. The plaintext never touches the audit log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application-level data is not recorded.&lt;/strong&gt; NEXUS AI audits actions taken on the platform — deployments, secrets, members, tokens. It does not audit what your application does with the resources it receives. If your app logs &lt;code&gt;process.env.DATABASE_URL&lt;/code&gt; at startup, that is an application-level concern, not a platform-level audit event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read operations on deployments are not individually logged.&lt;/strong&gt; Viewing a deployment's status in the dashboard does not produce an audit event. Audit events capture state changes and security-relevant reads (secrets, databases). Routine dashboard reads would generate millions of low-value INFO events per day on active organizations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Container stdout/stderr is not the audit log.&lt;/strong&gt; Build logs and runtime logs are separate from the audit log. They are accessible via &lt;code&gt;GET /api/deployments/:id/logs&lt;/code&gt; and stored in the observability layer, not in &lt;code&gt;audit_logs&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Checklist: audit log hygiene
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Review &lt;code&gt;GET /api/audit/security-summary&lt;/code&gt; weekly — if the score drops below 80, investigate&lt;/li&gt;
&lt;li&gt;[ ] Set &lt;code&gt;AUDIT_LOG_RETENTION_DAYS=365&lt;/code&gt; for HIPAA, financial, or PCI workloads (Enterprise plan)&lt;/li&gt;
&lt;li&gt;[ ] Export monthly CSVs to your compliance archive before the quarterly close&lt;/li&gt;
&lt;li&gt;[ ] Pull &lt;code&gt;GET /api/audit/user-activity/:userId&lt;/code&gt; for every departing team member as part of offboarding&lt;/li&gt;
&lt;li&gt;[ ] Filter for &lt;code&gt;PERMISSION_CHANGED&lt;/code&gt; events during quarterly access reviews — verify every role change was intentional&lt;/li&gt;
&lt;li&gt;[ ] Confirm no &lt;code&gt;SECRET_REVEALED&lt;/code&gt; events in the last 30 days unless explicitly authorized&lt;/li&gt;
&lt;li&gt;[ ] Set up a SIEM pipeline for &lt;code&gt;severity=WARNING&lt;/code&gt; events if your team size exceeds 10 engineers&lt;/li&gt;
&lt;li&gt;[ ] On Enterprise On-Prem: verify your PostgreSQL backup schedule includes the &lt;code&gt;audit_logs&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;[ ] Document your retention period in your security policy before your next audit&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I delete an audit log entry?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Audit log records are append-only. There is no API endpoint to delete individual records. The retention job purges records older than the retention window — but only non-CRITICAL events, and only automatically. This immutability is intentional: an audit log you can edit is not an audit log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who can access audit logs?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Audit log access requires the &lt;code&gt;audit.read&lt;/code&gt; org permission, which is granted to OWNER and ADMIN roles. Developer and lower roles cannot query the audit log. This prevents a Developer from inspecting what other users have done — audit visibility is a privilege, not a default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the audit log capture API calls made by NEXUS AI MCP tools (Claude agents)?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. MCP tool calls go through the same API layer as CLI and dashboard actions. They produce audit events with the token ID in &lt;code&gt;details.tokenId&lt;/code&gt; and a &lt;code&gt;userAgent&lt;/code&gt; that identifies the MCP client. You can filter for agent-originated actions by querying for the specific token ID issued to your MCP integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens to audit logs if I downgrade my plan?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Logs are not deleted on plan downgrade. If you downgrade from Enterprise (365-day retention) to Pro (90-day retention), the retention job will begin purging records older than 90 days on its next daily run. Export before downgrading if you need records beyond the 90-day window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the audit log encrypted at rest?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. The &lt;code&gt;audit_logs&lt;/code&gt; table lives in the same PostgreSQL database as the rest of your organization's data. The database is encrypted at rest using AES-256. On Enterprise On-Prem, encryption at rest is your infrastructure team's responsibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I receive real-time alerts for specific event types?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
CRITICAL events (SUSPICIOUS_ACTIVITY, CONTAINER_ESCAPE_ATTEMPT) trigger the alert pipeline immediately. For custom alerting on other event types — for example, an alert any time &lt;code&gt;PERMISSION_CHANGED&lt;/code&gt; fires — the current path is to poll &lt;code&gt;/api/audit/logs&lt;/code&gt; via your SIEM and configure alert rules there. Native webhook delivery for specific event types is on the product roadmap.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The audit log is available on every NEXUS AI plan, including Starter at $29/mo. The 90-day retention window, CSV export, and full API access ship on all plans. Configurable retention windows (&lt;code&gt;AUDIT_LOG_RETENTION_DAYS&lt;/code&gt;) and indefinite CRITICAL event retention are available on Enterprise and Enterprise On-Prem.&lt;/p&gt;

&lt;p&gt;If you are working through a HIPAA Business Associate Agreement, SOC 2 audit, or PCI self-assessment questionnaire, the compliance table in this post maps directly to the evidence your auditor needs. The CSV export at &lt;code&gt;/api/audit/export&lt;/code&gt; is the artifact.&lt;/p&gt;

&lt;p&gt;For regulated workloads, healthcare data, or financial applications, the Enterprise plan adds configurable retention, dedicated security review, and SAML SSO. Reach out at &lt;a href="https://nexusai.run" rel="noopener noreferrer"&gt;nexusai.run&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop shipping secrets. Start using a vault.&lt;/li&gt;
&lt;li&gt;RBAC deep dive: roles, scopes, and least privilege&lt;/li&gt;
&lt;li&gt;MCP integration: 37 tools for Claude and AI agents&lt;/li&gt;
&lt;li&gt;How NEXUS AI deploys your app in under 5 minutes&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;What you can't see, you can't defend. What you can't prove, you can't audit.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>web</category>
      <category>programming</category>
    </item>
    <item>
      <title>NEXUS AI GitHub Integration: The Complete Guide to Auto-Deploying from Your Repository</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:27:38 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-github-integration-the-complete-guide-to-auto-deploying-from-your-repository-11e</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/nexus-ai-github-integration-the-complete-guide-to-auto-deploying-from-your-repository-11e</guid>
      <description>&lt;h1&gt;
  
  
  NEXUS AI GitHub Integration: The Complete Guide to Auto-Deploying from Your Repository
&lt;/h1&gt;

&lt;p&gt;Connecting your GitHub repository to NEXUS AI unlocks a fully automated deployment pipeline — push code, and your app is live within minutes on GCP Cloud Run, AWS ECS Fargate, Azure Container Apps, or NEXUS AI Container. This guide walks through every step: installing the GitHub App, binding a repo, configuring auto-deploy rules, and understanding the webhook system that powers it all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Integrate GitHub with NEXUS AI?
&lt;/h2&gt;

&lt;p&gt;Modern software teams live in GitHub. Your pull requests, code reviews, branch strategies, and release tags all live there — so your deployment pipeline should follow that same source of truth.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;NEXUS AI GitHub integration&lt;/strong&gt; makes your repository the single trigger for deployments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No manual image builds or &lt;code&gt;docker push&lt;/code&gt; commands&lt;/li&gt;
&lt;li&gt;No CI pipeline boilerplate to maintain&lt;/li&gt;
&lt;li&gt;Branch-level control over which pushes trigger a deploy&lt;/li&gt;
&lt;li&gt;Encrypted environment variables stored securely at the binding level&lt;/li&gt;
&lt;li&gt;Full webhook audit trail — see every event NEXUS AI received from GitHub&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Install the NEXUS AI GitHub App
&lt;/h2&gt;

&lt;p&gt;To &lt;strong&gt;connect GitHub to NEXUS AI&lt;/strong&gt;, you need to install the NEXUS AI GitHub App on your GitHub account or organisation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to your NEXUS AI dashboard at &lt;a href="https://nexusai.run" rel="noopener noreferrer"&gt;nexusai.run&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Integrations → GitHub&lt;/strong&gt; (or open any project and click &lt;strong&gt;Connect GitHub&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Connect GitHub&lt;/strong&gt; button. You will be redirected to GitHub's App installation page.&lt;/li&gt;
&lt;li&gt;Choose whether to install on your personal account or a GitHub organisation.&lt;/li&gt;
&lt;li&gt;Select the repositories you want to grant access to (you can choose &lt;strong&gt;All repositories&lt;/strong&gt; or restrict to specific ones).&lt;/li&gt;
&lt;li&gt;Confirm the installation. GitHub will redirect you back to NEXUS AI with your installation ID automatically captured.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Required GitHub App Permissions
&lt;/h3&gt;

&lt;p&gt;The NEXUS AI GitHub App requests the minimum permissions needed to operate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Repository contents&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;Clone source code to build containers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Webhook events&lt;/td&gt;
&lt;td&gt;Push&lt;/td&gt;
&lt;td&gt;Receive push notifications to trigger deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No write access to your repository is ever requested. NEXUS AI only reads code and listens for push events.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Bind a Repository to a Deployment Target
&lt;/h2&gt;

&lt;p&gt;Once the app is installed, you need to &lt;strong&gt;bind a GitHub repo&lt;/strong&gt; to a deployment target in NEXUS AI. A binding links one branch (or set of branches) to one runtime environment with its own build configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Repo Binding
&lt;/h3&gt;

&lt;p&gt;In the NEXUS AI dashboard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Deployments → New Deployment&lt;/strong&gt; or open an existing project.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;GitHub&lt;/strong&gt; as the source.&lt;/li&gt;
&lt;li&gt;Choose your installed GitHub account/org and pick a repository from the dropdown.&lt;/li&gt;
&lt;li&gt;Configure the binding options below.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Repo Binding Configuration Options
&lt;/h3&gt;

&lt;p&gt;Each binding exposes the following fields:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Branch control&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allowedBranches&lt;/code&gt; — JSON array of branch names allowed to trigger deployments. Example: &lt;code&gt;["main", "production"]&lt;/code&gt;. Pushes to any other branch are silently ignored.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Deployment behaviour&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;autoDeploy&lt;/code&gt; — Boolean. When &lt;code&gt;true&lt;/code&gt;, every push to an allowed branch queues a deployment automatically. When &lt;code&gt;false&lt;/code&gt;, you must trigger deploys manually.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;projectId&lt;/code&gt; — Associate this binding with a NEXUS AI project for grouping and access control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Build configuration&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;buildMode&lt;/code&gt; — Build strategy. NEXUS AI auto-detects the language and framework, or you can override it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;installCommand&lt;/code&gt; — Dependency installation step. Example: &lt;code&gt;npm ci&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;buildCommand&lt;/code&gt; — Build step. Example: &lt;code&gt;npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;startCommand&lt;/code&gt; — Container entrypoint. Example: &lt;code&gt;node server.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outputDir&lt;/code&gt; — Build output directory (used for static sites and SSR frameworks).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;servicePort&lt;/code&gt; — The port your application listens on inside the container. Example: &lt;code&gt;3000&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Runtime target&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;runtimeTarget&lt;/code&gt; — Where to deploy the container. Options:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gcp_cloud_run&lt;/code&gt; — Google Cloud Run (serverless containers)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws_ecs_fargate&lt;/code&gt; — AWS ECS with Fargate (serverless containers)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;azure_container_apps&lt;/code&gt; — Azure Container Apps&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Container&lt;/code&gt; — NEXUS AI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Serving&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;subdomain&lt;/code&gt; — NEXUS AI-managed subdomain (e.g. &lt;code&gt;myapp.nexusai.run&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;customDomain&lt;/code&gt; — Your own domain (e.g. &lt;code&gt;app.example.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;envVars&lt;/code&gt; — Environment variables stored encrypted at rest. Never visible in logs or UI after saving.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Node.js App to GCP Cloud Run
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"allowedBranches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"autoDeploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runtimeTarget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gcp_cloud_run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"installCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm ci"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buildCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"startCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"servicePort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subdomain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"envVars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"NODE_ENV"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"DATABASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgresql://..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Enable Auto-Deploy from GitHub
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auto-deploying from GitHub&lt;/strong&gt; is controlled by two settings working together: &lt;code&gt;autoDeploy&lt;/code&gt; and &lt;code&gt;allowedBranches&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;autoDeploy: true&lt;/code&gt; and &lt;code&gt;allowedBranches: ["main"]&lt;/code&gt;, the full deployment flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You run &lt;code&gt;git push origin main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;GitHub sends a &lt;code&gt;push&lt;/code&gt; event webhook to &lt;code&gt;https://nexusai.run/api/github/webhook&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;NEXUS AI verifies the HMAC-SHA256 signature on the &lt;code&gt;x-hub-signature-256&lt;/code&gt; header to confirm the event is genuine&lt;/li&gt;
&lt;li&gt;NEXUS AI checks if the pushed branch (&lt;code&gt;main&lt;/code&gt;) is in your &lt;code&gt;allowedBranches&lt;/code&gt; list&lt;/li&gt;
&lt;li&gt;NEXUS AI checks that &lt;code&gt;autoDeploy&lt;/code&gt; is enabled on the binding&lt;/li&gt;
&lt;li&gt;A deployment job is queued and picked up by a worker (up to 5 concurrent builds per worker, polling every 2 seconds)&lt;/li&gt;
&lt;li&gt;Your container is built from source and pushed to the target runtime&lt;/li&gt;
&lt;li&gt;Status progresses through: &lt;code&gt;queued → building → deploying → success&lt;/code&gt; (or &lt;code&gt;failed&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Duplicate Commit Protection
&lt;/h3&gt;

&lt;p&gt;NEXUS AI deduplicates deployments by commit SHA. If you push the same commit twice (e.g. via a force-push that does not change the tree), NEXUS AI will not re-deploy it. Additionally, if a newer commit arrives while an older one is still queued, the older job is superseded — you always deploy the latest code, never a stale intermediate commit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Manual Deployments
&lt;/h2&gt;

&lt;p&gt;You do not have to rely on push webhooks. To trigger a deployment on demand:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Via the dashboard:&lt;/strong&gt; Open the binding and click the &lt;strong&gt;Deploy&lt;/strong&gt; button. NEXUS AI fetches the latest commit on the configured branch and queues a build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Via the REST API:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://nexusai.run/api/github/bindings/:bindingId/deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;your-api-token&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;:bindingId&lt;/code&gt; with the UUID of your repo binding, visible in the binding detail page URL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Understanding the Webhook System
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;push&lt;/code&gt; event GitHub sends to NEXUS AI is recorded in the &lt;strong&gt;Webhook Deliveries&lt;/strong&gt; tab of your binding. This gives you a full audit trail of what happened and why.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Can See
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Delivery ID&lt;/td&gt;
&lt;td&gt;GitHub's unique ID for the webhook delivery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event type&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;push&lt;/code&gt; for deployment triggers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ok&lt;/code&gt;, &lt;code&gt;ignored&lt;/code&gt;, or &lt;code&gt;failed&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reason&lt;/td&gt;
&lt;td&gt;Why the event was ignored (if applicable)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timestamp&lt;/td&gt;
&lt;td&gt;When the event was received&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Common "Ignored" Reasons
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;autoDeploy disabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The binding has &lt;code&gt;autoDeploy: false&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;branch not in allowedBranches&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The pushed branch is not in your allowed list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;installation suspended&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The GitHub App install was suspended by a GitHub admin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;duplicate commit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;This exact commit SHA was already deployed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The webhook endpoint is: &lt;strong&gt;&lt;code&gt;https://nexusai.run/api/github/webhook&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All payloads are verified using HMAC-SHA256 with a per-installation secret. Requests with an invalid or missing &lt;code&gt;x-hub-signature-256&lt;/code&gt; header are rejected immediately with no processing.&lt;/p&gt;




&lt;h2&gt;
  
  
  GitHub Actions Integration
&lt;/h2&gt;

&lt;p&gt;NEXUS AI does not replace GitHub Actions — it complements it. A common pattern is to run your test suite in GitHub Actions and only deploy when tests pass, using the NEXUS AI manual deploy API as the final step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/deploy.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test and Deploy&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Trigger NEXUS AI deployment&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;curl -X POST \&lt;/span&gt;
            &lt;span class="s"&gt;"https://nexusai.run/api/github/bindings/$NEXUS_BINDING_ID/deploy" \&lt;/span&gt;
            &lt;span class="s"&gt;-H "Authorization: Bearer $NEXUS_API_TOKEN" \&lt;/span&gt;
            &lt;span class="s"&gt;-H "Content-Type: application/json"&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;NEXUS_BINDING_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NEXUS_BINDING_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;NEXUS_API_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NEXUS_API_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;NEXUS_BINDING_ID&lt;/code&gt; and &lt;code&gt;NEXUS_API_TOKEN&lt;/code&gt; as GitHub Actions secrets in your repository settings (&lt;strong&gt;Settings → Secrets and variables → Actions&lt;/strong&gt;). With this pattern, set &lt;code&gt;autoDeploy: false&lt;/code&gt; on the NEXUS AI binding — deployments are controlled entirely by your Actions workflow, not raw push events.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Which GitHub plan do I need?&lt;/strong&gt;&lt;br&gt;
A: The NEXUS AI GitHub App works with free, Pro, Team, and Enterprise GitHub plans. It supports both personal accounts and organisations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I bind the same repo to multiple deployment targets?&lt;/strong&gt;&lt;br&gt;
A: Yes. You can create multiple bindings for the same repository — for example, one binding deploying &lt;code&gt;main&lt;/code&gt; to production on GCP Cloud Run and another deploying &lt;code&gt;staging&lt;/code&gt; to a Docker host.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I rotate my webhook secret?&lt;/strong&gt;&lt;br&gt;
A: Reinstall or refresh the GitHub App connection from the NEXUS AI integrations page. A new installation ID and secret are generated automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Are environment variables secure?&lt;/strong&gt;&lt;br&gt;
A: Yes. All values stored in &lt;code&gt;envVars&lt;/code&gt; on a binding are encrypted at rest using AES-256-GCM. They are injected into the container at runtime and never logged or exposed in the dashboard after the initial save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What happens if a deployment fails?&lt;/strong&gt;&lt;br&gt;
A: The deployment status is set to &lt;code&gt;failed&lt;/code&gt;. Your previous deployment continues running — NEXUS AI uses a rolling deployment strategy and never takes down a live container until a healthy replacement is confirmed. Build logs are available in the &lt;strong&gt;Deployments&lt;/strong&gt; tab and you can trigger a retry at any time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I disconnect GitHub?&lt;/strong&gt;&lt;br&gt;
A: You can suspend or uninstall the NEXUS AI GitHub App at any time from &lt;strong&gt;GitHub → Settings → Applications → Installed GitHub Apps&lt;/strong&gt;. In-flight deployments will complete; all future webhooks will be rejected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I use GitHub integration with a monorepo?&lt;/strong&gt;&lt;br&gt;
A: Yes. Use the &lt;code&gt;buildCommand&lt;/code&gt; and &lt;code&gt;outputDir&lt;/code&gt; fields to scope the build to a specific package or subdirectory. For example: &lt;code&gt;"buildCommand": "cd packages/api &amp;amp;&amp;amp; npm run build"&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;NEXUS AI GitHub integration&lt;/strong&gt; connects your repository to a fully automated, cloud-native deployment pipeline in three steps: install the GitHub App, create a repo binding with your target runtime and build configuration, then enable &lt;code&gt;autoDeploy&lt;/code&gt;. Every push to an allowed branch is cryptographically verified, deduplicated by commit SHA, and deployed — with a full webhook audit trail so you always know exactly what happened and why.&lt;/p&gt;

&lt;p&gt;For questions or support, visit the &lt;a href="https://nexusai.run/docs" rel="noopener noreferrer"&gt;NEXUS AI documentation&lt;/a&gt; or open a support ticket from your dashboard.&lt;/p&gt;

</description>
      <category>github</category>
      <category>integrations</category>
      <category>cicd</category>
      <category>tutorials</category>
    </item>
    <item>
      <title>MCP-driven deploys: 5 tasks your Claude agent should be running for you</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:25:45 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/mcp-driven-deploys-5-tasks-your-claude-agent-should-be-running-for-you-17ea</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/mcp-driven-deploys-5-tasks-your-claude-agent-should-be-running-for-you-17ea</guid>
      <description>&lt;h1&gt;
  
  
  MCP-driven deploys: 5 tasks your Claude agent should be running for you
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Published:&lt;/strong&gt; May 17, 2026&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; AI · MCP · Operations&lt;br&gt;
&lt;strong&gt;Reading time:&lt;/strong&gt; 8 minutes&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; NEXUS AI Team&lt;/p&gt;



&lt;p&gt;Most Model Context Protocol servers are read-only. They let your AI agent search a codebase, list GitHub issues, or look up Linear tickets. That is useful. It is also where most agents stop.&lt;/p&gt;

&lt;p&gt;NEXUS AI's MCP server is different. It exposes more than 50 write actions covering the full deployment lifecycle: build, deploy, scale, back up, restore, attach storage, query the database, fix schemas, roll back, and delete. Connect it to Claude Code, Cursor, Codex, or any MCP client, and your agent can run your infrastructure on your behalf.&lt;/p&gt;

&lt;p&gt;This post walks through five concrete tasks worth handing to your agent today.&lt;/p&gt;

&lt;p&gt;If your AI tools have only ever generated code for you, see also &lt;a href="https://nexusai.run/blog/your-ai-app-is-generated-now-how-do-you-deploy-it" rel="noopener noreferrer"&gt;Your AI app is generated. Now how do you deploy it?&lt;/a&gt; for the full picture of what changes when the agent owns operations.&lt;/p&gt;


&lt;h2&gt;
  
  
  Setup: connect the NEXUS AI MCP server in 60 seconds
&lt;/h2&gt;

&lt;p&gt;For Claude Desktop, add this to &lt;code&gt;~/Library/Application Support/Claude/claude_desktop_config.json&lt;/code&gt; (macOS) or &lt;code&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/code&gt; (Windows):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nexus-ai"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://nexusai.run/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer &amp;lt;your-nexus-token&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Cursor, add the same server in &lt;code&gt;Cursor Settings → MCP → Add server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Generate a token at &lt;code&gt;https://nexusai.run/app/tokens&lt;/code&gt;. Scopes follow &lt;code&gt;deployments:read|create|delete&lt;/code&gt;, &lt;code&gt;db:query|admin&lt;/code&gt;, &lt;code&gt;secrets:read|manage&lt;/code&gt;, and similar boundaries. Start with read-only scopes if you want to watch the agent before giving it write access.&lt;/p&gt;

&lt;p&gt;Restart your AI client. The 50+ NEXUS AI tools appear in its tool list.&lt;/p&gt;




&lt;h2&gt;
  
  
  Task 1: Deploy from a prompt
&lt;/h2&gt;

&lt;p&gt;The classic case. You have a repository with working code. Tell the agent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Deploy this repo to NEXUS AI. Use Postgres and Redis. Set the start command to &lt;code&gt;uvicorn app:app --host 0.0.0.0 --port 8000&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;nexusai_deploy_source&lt;/span&gt;
  &lt;span class="s"&gt;repo&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;           &lt;span class="s"&gt;https://github.com/you/my-app.git&lt;/span&gt;
  &lt;span class="s"&gt;framework&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;python&lt;/span&gt;
  &lt;span class="s"&gt;services&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;       &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;postgresql&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;start_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uvicorn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;app:app&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--port&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;8000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five minutes later the agent reports back with the live URL, the masked database connection string, and the deployment ID. You did not write a Dockerfile. You did not touch a dashboard.&lt;/p&gt;

&lt;p&gt;Why hand this over: the agent already has the repository context (it just wrote the code). It knows which framework, which port, which start command. The agent should know all of these without being told.&lt;/p&gt;




&lt;h2&gt;
  
  
  Task 2: Back up the database before a risky migration
&lt;/h2&gt;

&lt;p&gt;Your agent is about to run a schema migration. The right ops habit is "snapshot first, migrate second, validate third, restore on failure." That used to be three terminals, two Slack messages, and a prayer. Now it is one prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before running the migration on &lt;code&gt;my-ai-app&lt;/code&gt;, take a Postgres backup. If the migration fails, restore from the backup and roll back the deploy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. nexusai_db_services_list                 → finds the postgres service id
2. nexusai_db_backup                        → triggers pg_dump, waits for SUCCESS
3. (runs your migration command)
4. nexusai_deploy_logs                      → reads runtime logs for errors
5a. (success) nexusai_db_backup_list        → confirms backup is on the retention list
5b. (failure) nexusai_db_restore            → restores from the backup
              nexusai_deploy_rollback       → rolls back to the previous release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why hand this over: the failure path is the part humans forget to do under pressure. The agent always remembers.&lt;/p&gt;

&lt;p&gt;Backups land at &lt;code&gt;/var/lib/nexus-backups/&amp;lt;service&amp;gt;/&lt;/code&gt; and are downloadable through &lt;code&gt;nexusai_db_backup_download&lt;/code&gt;, which returns a signed URL with a 30 to 3600 second TTL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Task 3: Diagnose a failing deploy from logs
&lt;/h2&gt;

&lt;p&gt;A deployment is stuck in &lt;code&gt;BUILDING&lt;/code&gt; or healthy but throwing 500s. Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is wrong with &lt;code&gt;my-ai-app&lt;/code&gt; right now? Tail the last 200 log lines, identify the failure, and propose a fix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nexusai_deploy_status   → status, health, restart count, last error
nexusai_deploy_logs     → last 200 lines of build + runtime logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reads the actual stack trace, identifies the missing environment variable, the unhealthy upstream, or the failed migration, and replies with a targeted fix. If the fix is a code change, it edits the file in your IDE. If the fix is a secret, it calls &lt;code&gt;nexusai_secrets_create&lt;/code&gt;. If the fix is a redeploy, it calls &lt;code&gt;nexusai_deploy_redeploy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why hand this over: incident triage is the part of operations that scales worst with team size. An agent in the loop never forgets to check the logs first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Task 4: Query the database without leaving chat
&lt;/h2&gt;

&lt;p&gt;You want to know how many users signed up this week. You do not want to open &lt;code&gt;psql&lt;/code&gt;. Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How many users signed up in the last 7 days on &lt;code&gt;my-ai-app&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. nexusai_db_source_list           → resolves your database service
2. nexusai_db_inspect_schema        → confirms there is a `users` table with `created_at`
3. nexusai_db_query_preview         → returns the SQL it intends to run, you approve
4. nexusai_db_query_execute         → runs the read-only query, returns the count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The preview step is the safety net. You see the SQL before it runs. For read-only queries the agent runs in a sandboxed session with a 5-second statement timeout and a row-count cap. For destructive queries the agent uses the AI-powered DDL fix workflow (&lt;code&gt;nexusai_db_propose_fix&lt;/code&gt; then &lt;code&gt;nexusai_db_apply_fix&lt;/code&gt;), which requires explicit approval.&lt;/p&gt;

&lt;p&gt;Why hand this over: most "look at the database" tasks are short, repetitive, and high-friction. Making them a chat message removes the friction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Task 5: Roll back on incident
&lt;/h2&gt;

&lt;p&gt;A deploy went out at 3pm. Error rates spiked at 3:05. Tell the agent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Roll back &lt;code&gt;my-ai-app&lt;/code&gt; to the previous release. Snapshot Postgres first in case we need to forward-fix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. nexusai_db_backup           → snapshot before the rollback
2. nexusai_deploy_rollback     → revert to the previous container image
3. nexusai_deploy_status       → confirm RUNNING and healthy
4. nexusai_deploy_logs         → tail to verify error rate dropped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rollback flips back to the previous image with the same database state. If the bug was schema-level you can restore from the backup separately.&lt;/p&gt;

&lt;p&gt;Why hand this over: rollbacks under stress are exactly when humans skip the snapshot step.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you should not hand over yet
&lt;/h2&gt;

&lt;p&gt;A few actions are deliberately gated. The agent can prepare them but cannot fire them without explicit confirmation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Why gated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Delete a deployment (&lt;code&gt;nexusai_deploy_delete&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Permanent. Tears down containers, networks, volumes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drop or truncate via &lt;code&gt;nexusai_db_query_execute&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Requires &lt;code&gt;db:admin&lt;/code&gt; scope and an explicit confirmation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete a bucket (&lt;code&gt;nexusai_bucket_delete&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Removes scoped service account and bucket contents.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove a volume (&lt;code&gt;nexusai_volume_delete&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Deletes the underlying data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate bucket credentials&lt;/td&gt;
&lt;td&gt;Invalidates current keys. Apps must redeploy.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The platform requires the agent to call a &lt;code&gt;_preview&lt;/code&gt; variant first (where available) or to set an explicit &lt;code&gt;confirm: true&lt;/code&gt; flag. The agent will pause and ask you before crossing one of these lines.&lt;/p&gt;




&lt;h2&gt;
  
  
  A minimal Claude system prompt for operations
&lt;/h2&gt;

&lt;p&gt;If you want Claude to behave as a careful operator rather than an enthusiastic deployer, paste this into your project's system instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are operating a NEXUS AI account via MCP tools. Rules:

1. Read before you write. Always call status/list/inspect tools before
   making changes.
2. Snapshot before destructive operations. Always call nexusai_db_backup
   before migrations or restores.
3. Show the SQL before running it. Always call nexusai_db_query_preview
   before nexusai_db_query_execute.
4. Confirm before deletes. Never call delete tools without an explicit
   "yes, delete &amp;lt;resource&amp;gt;" from the user in the same message.
5. Prefer rollback over fix-forward during an incident. Stabilize first,
   debug second.
6. Stream logs after every deploy or restart and summarize the first
   error you see.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six lines turn a code-generating agent into an operations partner.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this changes about your workflow
&lt;/h2&gt;

&lt;p&gt;Once the agent can deploy and operate, three things shift:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operations cost drops.&lt;/strong&gt; Tasks that took 5 to 30 minutes (snapshot, deploy, tail logs, rollback) become one prompt. The agent does the boilerplate, you make the decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incident response gets faster.&lt;/strong&gt; The agent already has context (recent code changes, recent deploys, recent logs). It can triage in seconds instead of minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Experimentation gets cheaper.&lt;/strong&gt; Standing up a new app, attaching a database, testing an idea, tearing it down: each step is one prompt instead of one ticket.&lt;/p&gt;

&lt;p&gt;The agent is no longer a code-completion tool. It is the operator on call.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which MCP clients work with NEXUS AI?&lt;/strong&gt;&lt;br&gt;
Claude Desktop, Claude Code, Cursor, Codex CLI, Windsurf, Zed AI, and any client that speaks MCP over HTTP or stdio. NEXUS AI publishes a hosted HTTPS endpoint, so any client that can attach a Bearer token works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the agent need the same permissions I have?&lt;/strong&gt;&lt;br&gt;
No. NEXUS AI tokens are scoped. Start the agent with &lt;code&gt;deployments:read&lt;/code&gt;, &lt;code&gt;db:read&lt;/code&gt;, &lt;code&gt;logs:read&lt;/code&gt;. Promote scopes only when you want it to deploy or modify. Tokens are revocable from the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can two agents operate the same account?&lt;/strong&gt;&lt;br&gt;
Yes. Each token is independent. Audit log entries record which token took each action, so you can attribute changes to "claude-prod", "cursor-staging", or any other label.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a rate limit on MCP calls?&lt;/strong&gt;&lt;br&gt;
The platform applies standard API rate limits per token. Heavy reconciliation loops should batch (&lt;code&gt;*_list&lt;/code&gt; tools support pagination) instead of polling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the agent see secret values?&lt;/strong&gt;&lt;br&gt;
No. &lt;code&gt;nexusai_secrets_list&lt;/code&gt; returns names and metadata. &lt;code&gt;nexusai_secrets_create&lt;/code&gt; accepts values you provide. The platform never returns decrypted secret values over the API or MCP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if the agent makes a mistake?&lt;/strong&gt;&lt;br&gt;
Every action is in the audit log (&lt;code&gt;AuditLog&lt;/code&gt; table, exportable from the dashboard). Most actions are reversible: stops have starts, deploys have rollbacks, backups have restores. Deletes are the only one-way door, and the agent will not call delete tools without explicit user confirmation in the same message.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://nexusai.run/register" rel="noopener noreferrer"&gt;Start free&lt;/a&gt; and connect the MCP server in your client of choice. Or ask your agent to do it for you.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claude</category>
      <category>cursor</category>
      <category>agents</category>
    </item>
    <item>
      <title>Persistent storage in NEXUS AI</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:24:13 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/persistent-storage-in-nexus-ai-2nbp</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/persistent-storage-in-nexus-ai-2nbp</guid>
      <description>&lt;h1&gt;
  
  
  Persistent storage in NEXUS AI: volumes and S3-compatible buckets for deployed apps
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Published:&lt;/strong&gt; May 9, 2026&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Storage · DevOps&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Reading time:&lt;/strong&gt; 11 minutes&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; NEXUS AI Team&lt;/p&gt;



&lt;p&gt;Most application deployment platforms make stateless services easy and stateful workloads awkward. That works until your app needs user uploads, generated reports, SQLite files, model artifacts, or a shared object store for background jobs.&lt;/p&gt;

&lt;p&gt;NEXUS AI now includes two storage primitives for deployed applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Volumes&lt;/strong&gt; for persistent filesystem mounts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buckets&lt;/strong&gt; for S3-compatible object storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are organization-scoped. Both can be attached to deployments. Both survive container restarts, redeploys, and deployment deletion until you explicitly delete the storage resource.&lt;/p&gt;

&lt;p&gt;This post explains when to use each one, how to attach them, how they behave during scaling, and the exact CLI commands to run.&lt;/p&gt;


&lt;h2&gt;
  
  
  Two storage primitives
&lt;/h2&gt;

&lt;p&gt;Volumes and buckets solve different problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Access pattern&lt;/th&gt;
&lt;th&gt;Attachment model&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Volumes&lt;/td&gt;
&lt;td&gt;Filesystem state, SQLite, local uploads, persistent caches&lt;/td&gt;
&lt;td&gt;App reads and writes a mounted path like &lt;code&gt;/data&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Single deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buckets&lt;/td&gt;
&lt;td&gt;User media, reports, generated assets, object storage&lt;/td&gt;
&lt;td&gt;App uses S3-compatible SDK calls&lt;/td&gt;
&lt;td&gt;Multiple deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use a &lt;strong&gt;volume&lt;/strong&gt; when your app expects a local filesystem path.&lt;/p&gt;

&lt;p&gt;Use a &lt;strong&gt;bucket&lt;/strong&gt; when your app can store data as objects by key using an S3 SDK.&lt;/p&gt;


&lt;h2&gt;
  
  
  Volumes: persistent filesystem mounts
&lt;/h2&gt;

&lt;p&gt;A NEXUS AI volume is a persistent filesystem mount backed by a Docker named volume. Your app writes to a path, usually &lt;code&gt;/data&lt;/code&gt;, and the data remains available after redeploys or container replacement.&lt;/p&gt;

&lt;p&gt;Create a volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus volume create app-data &lt;span class="nt"&gt;--display-name&lt;/span&gt; &lt;span class="s2"&gt;"App data"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your-org/your-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; myapp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attach the volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus volume attach &amp;lt;volume-id&amp;gt; &amp;lt;deployment-id&amp;gt; &lt;span class="nt"&gt;--mount&lt;/span&gt; /data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redeploy so the new container starts with the mount:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy redeploy &amp;lt;deployment-id&amp;gt; &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That redeploy step matters. Docker mounts are applied when a container is created. You cannot add a volume mount to an already-running container.&lt;/p&gt;

&lt;p&gt;Verify the mount:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;container-id&amp;gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  When to use volumes
&lt;/h2&gt;

&lt;p&gt;Volumes are a good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite databases for small apps.&lt;/li&gt;
&lt;li&gt;User uploads written through the filesystem.&lt;/li&gt;
&lt;li&gt;Persistent cache directories.&lt;/li&gt;
&lt;li&gt;Generated files that your app expects to read from disk.&lt;/li&gt;
&lt;li&gt;Model files or local indexes that survive redeploys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Volumes are not a good fit for every scaled workload. If multiple app replicas write the same file at the same time, your application needs to handle locking or coordination.&lt;/p&gt;

&lt;p&gt;Think of a NEXUS AI volume like a shared network drive. It persists, but it does not magically make unsafe concurrent writes safe.&lt;/p&gt;




&lt;h2&gt;
  
  
  How volumes behave when you scale
&lt;/h2&gt;

&lt;p&gt;When you scale a deployment up, every replica mounts the same named volume at the same path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy scale &amp;lt;deployment-id&amp;gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three replicas now see the same files under &lt;code&gt;/data&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is useful for read-mostly data, shared assets, or workloads with explicit locking. It is risky for apps that assume a single writer, such as a default SQLite setup with multiple write-heavy replicas.&lt;/p&gt;

&lt;p&gt;When you scale down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy scale &amp;lt;deployment-id&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The removed containers detach. The volume remains. The remaining replica keeps using the same data.&lt;/p&gt;

&lt;p&gt;When you delete the deployment, the volume still survives. You must explicitly detach and delete the volume if you want to destroy the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus volume detach &amp;lt;volume-id&amp;gt;
nexus volume delete &amp;lt;volume-id&amp;gt; &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Buckets: S3-compatible object storage
&lt;/h2&gt;

&lt;p&gt;A NEXUS AI bucket is S3-compatible object storage backed by MinIO. Your app interacts with it using standard AWS SDKs, boto3, or any S3-compatible client.&lt;/p&gt;

&lt;p&gt;Create a bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket create user-uploads &lt;span class="nt"&gt;--display-name&lt;/span&gt; &lt;span class="s2"&gt;"User uploads"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attach it to a deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket attach &amp;lt;bucket-id&amp;gt; &amp;lt;deployment-id&amp;gt;
nexus deploy redeploy &amp;lt;deployment-id&amp;gt; &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After redeploy, NEXUS AI injects S3 environment variables into the app container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;S3_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://host.docker.internal:9000
&lt;span class="nv"&gt;S3_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;span class="nv"&gt;S3_BUCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;org-&amp;lt;orgIdShort&amp;gt;-&amp;lt;bucketName&amp;gt;
&lt;span class="nv"&gt;S3_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;scoped access key&amp;gt;
&lt;span class="nv"&gt;S3_SECRET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;scoped secret key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If multiple buckets are attached, NEXUS AI also injects per-bucket aliases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;S3_BUCKET_USER_UPLOADS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;org-...-user-uploads
&lt;span class="nv"&gt;S3_BUCKET_USER_UPLOADS_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;span class="nv"&gt;S3_BUCKET_USER_UPLOADS_SECRET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Example: write files to a bucket from Python
&lt;/h2&gt;

&lt;p&gt;Your app can use boto3 with the injected environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3_ENDPOINT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3_SECRET_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3_BUCKET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uploads/hello.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello from NEXUS AI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That same pattern works with the AWS SDK for JavaScript, Go, Java, Ruby, PHP, and other S3-compatible clients.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bucket file operations from the CLI
&lt;/h2&gt;

&lt;p&gt;List files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket files &amp;lt;bucket-id&amp;gt;
nexus bucket files &amp;lt;bucket-id&amp;gt; &lt;span class="nt"&gt;--prefix&lt;/span&gt; uploads/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket upload &amp;lt;bucket-id&amp;gt; ./report.pdf &lt;span class="nt"&gt;--key&lt;/span&gt; reports/report.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Download a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket download &amp;lt;bucket-id&amp;gt; reports/report.pdf &lt;span class="nt"&gt;--out&lt;/span&gt; ./report.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate a short-lived signed download URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket download &amp;lt;bucket-id&amp;gt; reports/report.pdf &lt;span class="nt"&gt;--share&lt;/span&gt; &lt;span class="nt"&gt;--ttl&lt;/span&gt; 900
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Delete a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket &lt;span class="nb"&gt;rm&lt;/span&gt; &amp;lt;bucket-id&amp;gt; reports/report.pdf &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI upload path streams from disk, which is better for large files than browser uploads.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scoped credentials and rotation
&lt;/h2&gt;

&lt;p&gt;Each bucket gets scoped S3 credentials. A deployment attached to one bucket does not automatically get access to every bucket in the organization.&lt;/p&gt;

&lt;p&gt;Reveal credentials for external clients:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket credentials &amp;lt;bucket-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rotate credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket rotate-credentials &amp;lt;bucket-id&amp;gt; &lt;span class="nt"&gt;--yes&lt;/span&gt;
nexus deploy redeploy &amp;lt;deployment-id&amp;gt; &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redeploy is required because the running container already has the old environment variables. The next container start receives the new &lt;code&gt;S3_ACCESS_KEY&lt;/code&gt; and &lt;code&gt;S3_SECRET_KEY&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Buckets and scaling
&lt;/h2&gt;

&lt;p&gt;Buckets are usually a better fit for scaled apps than shared filesystem volumes.&lt;/p&gt;

&lt;p&gt;When you scale up, every replica receives the same S3 environment variables. Each replica makes independent S3 API calls. The object storage layer handles concurrent requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy scale &amp;lt;deployment-id&amp;gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For object keys, the normal S3 rule applies: if two replicas write the same key, the last write wins. Use unique keys when each replica should produce independent output.&lt;/p&gt;

&lt;p&gt;When you scale down, nothing needs to detach. The removed container stops making S3 calls. The bucket and objects remain.&lt;/p&gt;




&lt;h2&gt;
  
  
  REST API reference
&lt;/h2&gt;

&lt;p&gt;Volumes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET    /api/volumes
POST   /api/volumes
POST   /api/volumes/:id/attach
POST   /api/volumes/:id/detach
POST   /api/volumes/:id/refresh-usage
DELETE /api/volumes/:id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Buckets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET    /api/buckets
POST   /api/buckets
POST   /api/buckets/:id/attach
POST   /api/buckets/:id/detach
POST   /api/buckets/:id/refresh-usage
POST   /api/buckets/:id/rotate-credentials
GET    /api/buckets/:id/credentials
GET    /api/buckets/:id/files
PUT    /api/buckets/:id/files/:key
GET    /api/buckets/:id/files/:key/download
POST   /api/buckets/:id/files/:key/download-url
DELETE /api/buckets/:id/files/:key
GET    /api/bucket-downloads/:token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example volume attach request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_BASE&lt;/span&gt;&lt;span class="s2"&gt;/volumes/&amp;lt;volume-id&amp;gt;/attach"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_JWT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"deploymentId":"&amp;lt;deployment-id&amp;gt;","mountPath":"/data"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example bucket attach request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_API_BASE&lt;/span&gt;&lt;span class="s2"&gt;/buckets/&amp;lt;bucket-id&amp;gt;/attach"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$NEXUS_JWT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"deploymentId":"&amp;lt;deployment-id&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  MCP tools
&lt;/h2&gt;

&lt;p&gt;AI clients can operate storage through MCP tools with scoped permissions.&lt;/p&gt;

&lt;p&gt;Volume tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nexusai_volume_list
nexusai_volume_create
nexusai_volume_attach
nexusai_volume_detach
nexusai_volume_delete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bucket tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nexusai_bucket_list
nexusai_bucket_create
nexusai_bucket_attach
nexusai_bucket_detach
nexusai_bucket_rotate_credentials
nexusai_bucket_files_list
nexusai_bucket_file_download
nexusai_bucket_file_delete
nexusai_bucket_delete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use MCP for operational flows like “create a bucket for this deployment, attach it, then remind me to redeploy,” while keeping destructive operations behind confirmation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which one should you choose?
&lt;/h2&gt;

&lt;p&gt;Choose a &lt;strong&gt;volume&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app requires a filesystem path.&lt;/li&gt;
&lt;li&gt;You need persistent local files.&lt;/li&gt;
&lt;li&gt;You are running a single replica or have safe file-locking behavior.&lt;/li&gt;
&lt;li&gt;You want simple persistence for Docker-based deployments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose a &lt;strong&gt;bucket&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app stores uploads or generated files.&lt;/li&gt;
&lt;li&gt;Multiple deployments need access to the same storage.&lt;/li&gt;
&lt;li&gt;The app may scale to multiple replicas.&lt;/li&gt;
&lt;li&gt;You want S3-compatible tooling and signed URLs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most user-upload and generated-asset workflows, buckets are the better long-term default. For apps that truly expect local disk, volumes are the practical answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;NEXUS AI now gives deployed apps durable storage without forcing every app into the same model.&lt;/p&gt;

&lt;p&gt;Volumes give you persistent filesystem mounts. Buckets give you S3-compatible object storage with scoped credentials, file operations, signed URLs, and multi-deployment attachment.&lt;/p&gt;

&lt;p&gt;The rule is simple: use volumes for local filesystem state, and use buckets for object storage. Then redeploy after attaching so your containers receive the mount or environment variables they need.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>s3</category>
      <category>nexusai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Deploy a full-stack Python app with Postgres, Redis, and workers in 5 minutes</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:21:53 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/deploy-a-full-stack-python-app-with-postgres-redis-and-workers-in-5-minutes-je1</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/deploy-a-full-stack-python-app-with-postgres-redis-and-workers-in-5-minutes-je1</guid>
      <description>&lt;h2&gt;
  
  
  Deploy a full-stack Python app with Postgres, Redis, and workers in 5 minutes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Published:&lt;/strong&gt; May 15, 2026&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Python · DevOps · Databases&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Reading time:&lt;/strong&gt; 8 minutes&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; NEXUS AI Team&lt;/p&gt;

&lt;p&gt;Most Python apps are not just one web process.&lt;/p&gt;

&lt;p&gt;Even a small production app usually needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A web API, often FastAPI, Flask, or Django.&lt;/li&gt;
&lt;li&gt;PostgreSQL for durable application data.&lt;/li&gt;
&lt;li&gt;Redis for queues, caching, rate limits, or sessions.&lt;/li&gt;
&lt;li&gt;A background worker for slow jobs like emails, scraping, AI calls, imports, PDF generation, or webhook processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The painful part is usually not the code. It is wiring the app container, database, cache, worker process, service networking, ports, health checks, environment variables, volumes, logs, and scaling rules.&lt;/p&gt;

&lt;p&gt;With the NEXUS AI CLI, you can deploy the whole stack from a Git repository with one command.&lt;/p&gt;

&lt;p&gt;This post walks through a practical Python deployment using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python web app&lt;/li&gt;
&lt;li&gt;PostgreSQL service&lt;/li&gt;
&lt;li&gt;Redis service&lt;/li&gt;
&lt;li&gt;RQ background worker&lt;/li&gt;
&lt;li&gt;Internal service networking&lt;/li&gt;
&lt;li&gt;Scaling&lt;/li&gt;
&lt;li&gt;Logs&lt;/li&gt;
&lt;li&gt;Backup&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What we are deploying
&lt;/h2&gt;

&lt;p&gt;The target architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
  |
  v
NEXUS AI 
  |
  v
Python web container
  |-- connects to postgresql:5432
  |-- connects to redis:6379
  |
  v
Worker container
  |-- runs rq worker default
  |-- connects to the same Postgres and Redis services

PostgreSQL container
Redis container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important detail: the app and worker do not connect to &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside the deployment network, the database hostnames are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postgresql:5432
redis:6379
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEXUS AI injects the environment variables your app needs, including &lt;code&gt;DATABASE_URL&lt;/code&gt; and &lt;code&gt;REDIS_URL&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A NEXUS AI account.&lt;/li&gt;
&lt;li&gt;The NEXUS CLI installed.&lt;/li&gt;
&lt;li&gt;A Git repository containing your Python app.&lt;/li&gt;
&lt;li&gt;A Python app that listens on a known port, usually &lt;code&gt;8000&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://nexusai.run/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://nexusai.run/install-mac.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authenticate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus auth login
nexus auth status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Python app structure
&lt;/h2&gt;

&lt;p&gt;Your repository can be simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-python-app/
  app.py
  worker.py
  requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastapi
uvicorn[standard]
psycopg[binary]
redis
rq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;app.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Redis&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rq&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;redis_conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REDIS_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;redis_conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;processed &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/healthz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;healthz&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/jobs/{name}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;enqueue_job&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queued&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;worker.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Redis&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rq&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;

&lt;span class="n"&gt;redis_conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REDIS_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;redis_conn&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;redis_conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a real app, your task functions usually live in a separate module so both the web process and worker can import them cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the full stack
&lt;/h2&gt;

&lt;p&gt;Run one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your-org/my-python-app.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-python-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; python &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--branch&lt;/span&gt; main &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--services&lt;/span&gt; postgresql,redis &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-command&lt;/span&gt; &lt;span class="s2"&gt;"uvicorn app:app --host 0.0.0.0 --port 8000"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"python worker.py"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-name&lt;/span&gt; jobs-worker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command does the operational work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pulls your Git repository.&lt;/li&gt;
&lt;li&gt;Detects/builds the Python app image.&lt;/li&gt;
&lt;li&gt;Creates the web app container.&lt;/li&gt;
&lt;li&gt;Creates a PostgreSQL service.&lt;/li&gt;
&lt;li&gt;Creates a Redis service.&lt;/li&gt;
&lt;li&gt;Creates a worker container from the same app image.&lt;/li&gt;
&lt;li&gt;Attaches the app, worker, Postgres, and Redis to the same service network.&lt;/li&gt;
&lt;li&gt;Injects database and Redis environment variables.&lt;/li&gt;
&lt;li&gt;Exposes only the web app publicly.&lt;/li&gt;
&lt;li&gt;Keeps the worker private.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The worker does not need a public port. It runs inside the same deployment network and talks to Redis/Postgres by internal hostname.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment variables your app receives
&lt;/h2&gt;

&lt;p&gt;For PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POSTGRES_HOST=postgresql
POSTGRES_PORT=5432
POSTGRES_DB=appdb
POSTGRES_USER=appuser
POSTGRES_PASSWORD=&amp;lt;generated&amp;gt;
DATABASE_URL=postgresql://appuser:&amp;lt;generated&amp;gt;@postgresql:5432/appdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Redis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REDIS_HOST=redis
REDIS_PORT=6379
REDIS_URL=redis://redis:6379/0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use these values inside the app and worker.&lt;/p&gt;

&lt;p&gt;Do not hardcode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost
127.0.0.1
host.docker.internal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those point to the wrong place from inside a container. Use &lt;code&gt;postgresql&lt;/code&gt; and &lt;code&gt;redis&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check deployment status
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy status my-python-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the deployment move through states such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING
BUILDING
RUNNING
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it is running, open the deployment URL and check the health route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://your-app-url/healthz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Watch app and worker logs
&lt;/h2&gt;

&lt;p&gt;Tail logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy logs my-python-app &lt;span class="nt"&gt;--follow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your worker is connected correctly, you should see it listening on the queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Listening on default...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the worker cannot resolve Redis, you will see errors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error -2 connecting to redis:6379. Name or service not known.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That usually means the worker was not attached to the deployment network or the app is using the wrong Redis hostname.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;REDIS_URL=redis://redis:6379/0&lt;/code&gt;, not &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test the queue
&lt;/h2&gt;

&lt;p&gt;Send a job to the web app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://your-app-url/jobs/demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"job_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"queued"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy logs my-python-app &lt;span class="nt"&gt;--follow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the worker pick up the job.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scale the web app
&lt;/h2&gt;

&lt;p&gt;Scale the web containers to two replicas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy scale my-python-app 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scale to three:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy scale my-python-app 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scale back down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy scale my-python-app 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scaling changes the web app replicas. PostgreSQL and Redis are not duplicated. They remain the shared backing services for the deployment.&lt;/p&gt;

&lt;p&gt;This matters because a scaled Python app should be stateless at the web layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store durable data in Postgres.&lt;/li&gt;
&lt;li&gt;Store queue/cache/session data in Redis.&lt;/li&gt;
&lt;li&gt;Store uploaded files in a bucket or attached volume.&lt;/li&gt;
&lt;li&gt;Do not rely on local container files unless you intentionally attached persistent storage.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Add production environment variables
&lt;/h2&gt;

&lt;p&gt;Pass runtime variables directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your-org/my-python-app.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-python-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; python &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--services&lt;/span&gt; postgresql,redis &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;APP_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;QUEUE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"python worker.py"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or load them from a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your-org/my-python-app.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-python-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; python &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--services&lt;/span&gt; postgresql,redis &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env.production &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"python worker.py"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For sensitive values, use the secrets vault instead of committing &lt;code&gt;.env&lt;/code&gt; files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus secret create OPENAI_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reference secrets during deployment or from the dashboard, depending on your workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Back up Postgres
&lt;/h2&gt;

&lt;p&gt;List database services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus db services my-python-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a backup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus db backup &amp;lt;postgres-service-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List backups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus db backups &amp;lt;postgres-service-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Download a backup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus db backup-download &amp;lt;postgres-service-id&amp;gt; &amp;lt;backup-id&amp;gt; &lt;span class="nt"&gt;--out&lt;/span&gt; ./postgres.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restore into the same service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus db restore &amp;lt;postgres-service-id&amp;gt; &amp;lt;backup-id&amp;gt; &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restore into another deployment's Postgres service in the same organization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus db restore-to &amp;lt;target-postgres-service-id&amp;gt; &amp;lt;backup-id&amp;gt; &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before restoring production data, pause write-heavy workers or scale them down if your workflow supports it. A restore can replace database state.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common fixes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The app cannot connect to Postgres
&lt;/h3&gt;

&lt;p&gt;Check that the app is using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL=postgresql://appuser:&amp;lt;password&amp;gt;@postgresql:5432/appdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hostname must be &lt;code&gt;postgresql&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The worker cannot connect to Redis
&lt;/h3&gt;

&lt;p&gt;Check that the worker is using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REDIS_URL=redis://redis:6379/0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hostname must be &lt;code&gt;redis&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The worker starts, then exits
&lt;/h3&gt;

&lt;p&gt;Make sure the worker command is a long-running process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"python worker.py"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"rq worker default"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not use a one-shot command unless you intentionally want a short task.&lt;/p&gt;

&lt;h3&gt;
  
  
  The app deploys, but health checks fail
&lt;/h3&gt;

&lt;p&gt;Confirm the app listens on &lt;code&gt;0.0.0.0&lt;/code&gt;, not &lt;code&gt;127.0.0.1&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvicorn app:app &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0 &lt;span class="nt"&gt;--port&lt;/span&gt; 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also make sure the app exposes a health endpoint such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/healthz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scaling up works, but file uploads disappear
&lt;/h3&gt;

&lt;p&gt;Local container files are ephemeral. Use a NEXUS AI bucket for user uploads or a persistent volume for filesystem-backed data.&lt;/p&gt;

&lt;p&gt;For object storage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus bucket create user-uploads &lt;span class="nt"&gt;--display-name&lt;/span&gt; &lt;span class="s2"&gt;"User uploads"&lt;/span&gt;
nexus bucket attach &amp;lt;bucket-id&amp;gt; &amp;lt;deployment-id&amp;gt;
nexus deploy redeploy &amp;lt;deployment-id&amp;gt; &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The 5-minute path
&lt;/h2&gt;

&lt;p&gt;If your app already has a working Python web process and worker command, the full deployment is one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your-org/my-python-app.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-python-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; python &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--services&lt;/span&gt; postgresql,redis &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-command&lt;/span&gt; &lt;span class="s2"&gt;"uvicorn app:app --host 0.0.0.0 --port 8000"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"python worker.py"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-name&lt;/span&gt; jobs-worker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy status my-python-app
nexus deploy logs my-python-app &lt;span class="nt"&gt;--follow&lt;/span&gt;
curl https://your-app-url/healthz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the core workflow: deploy the web app, provision Postgres and Redis, attach the worker to the same network, and manage the whole stack from the CLI.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I use Celery instead of RQ?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. Use a Celery worker command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"celery -A app.celery worker --loglevel=info"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Does the worker get the same environment variables as the app?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. The worker uses the same built image and receives the same deployment environment variables, including database and Redis connection values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does scaling duplicate Postgres or Redis?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Scaling changes app replicas. Database and cache services remain shared deployment resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should the worker expose a port?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Workers should stay private. They consume jobs from Redis and do not need public ingress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I deploy Django with this pattern?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. Use a Django web command such as &lt;code&gt;gunicorn config.wsgi:application --bind 0.0.0.0:8000&lt;/code&gt; and a worker command such as &lt;code&gt;celery -A config worker --loglevel=info&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use this with private GitHub repositories?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. Store your repository token as a secret and deploy with &lt;code&gt;--repo-secret&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your-org/private-python-app.git &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo-secret&lt;/span&gt; GITHUB_TOKEN &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; private-python-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--framework&lt;/span&gt; python &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--services&lt;/span&gt; postgresql,redis &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-command&lt;/span&gt; &lt;span class="s2"&gt;"python worker.py"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ai</category>
      <category>python</category>
      <category>redis</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Replace Github Actions With One Command</title>
      <dc:creator>Saif Ali</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:18:49 +0000</pubDate>
      <link>https://dev.to/sali_ac161a1b71406354896c/replace-github-actions-with-one-command-3p1o</link>
      <guid>https://dev.to/sali_ac161a1b71406354896c/replace-github-actions-with-one-command-3p1o</guid>
      <description>&lt;p&gt;My GitHub Actions deploy workflow was 87 lines of YAML.&lt;/p&gt;

&lt;p&gt;It had grown over 18 months from a clean 20-line file into something I was genuinely afraid to touch. It broke whenever a dependency updated. It had three hardcoded ARNs from an AWS account I was no longer using. It had a comment that said &lt;code&gt;# TODO: fix this&lt;/code&gt; that had been there for 11 months.&lt;/p&gt;

&lt;p&gt;Last month I deleted all 87 lines and replaced them with one command.&lt;/p&gt;

&lt;p&gt;Here's exactly how I did it — and what I learned along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The YAML graveyard
&lt;/h2&gt;

&lt;p&gt;This was my deploy workflow. See if any of this feels familiar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Production&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Login to Amazon ECR&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;login-ecr&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecr-login@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Docker image&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ECR_REGISTRY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.login-ecr.outputs.registry }}&lt;/span&gt;
          &lt;span class="na"&gt;IMAGE_TAG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.sha }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;docker build -t $ECR_REGISTRY/my-app:$IMAGE_TAG .&lt;/span&gt;
          &lt;span class="s"&gt;docker push $ECR_REGISTRY/my-app:$IMAGE_TAG&lt;/span&gt;
          &lt;span class="s"&gt;echo "IMAGE=$ECR_REGISTRY/my-app:$IMAGE_TAG" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download task definition&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;aws ecs describe-task-definition --task-definition my-app \&lt;/span&gt;
            &lt;span class="s"&gt;--query taskDefinition &amp;gt; task-definition.json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update ECS task definition&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task-def&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecs-render-task-definition@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;task-definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task-definition.json&lt;/span&gt;
          &lt;span class="na"&gt;container-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.IMAGE }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to ECS&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/amazon-ecs-deploy-task-definition@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;task-definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.task-def.outputs.task-definition }}&lt;/span&gt;
          &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app-service&lt;/span&gt;
          &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app-cluster&lt;/span&gt;
          &lt;span class="na"&gt;wait-for-service-stability&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Notify on failure&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;failure()&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \&lt;/span&gt;
            &lt;span class="s"&gt;-H 'Content-type: application/json' \&lt;/span&gt;
            &lt;span class="s"&gt;--data '{"text":"Deploy failed! Check Actions."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wrote this. I'm not proud of it.&lt;/p&gt;

&lt;p&gt;The real problem wasn't the YAML itself. The problem was everything hidden &lt;em&gt;underneath&lt;/em&gt; the YAML:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An ECR repository I had to provision manually&lt;/li&gt;
&lt;li&gt;An ECS cluster, service, and task definition I had to set up in the console&lt;/li&gt;
&lt;li&gt;IAM roles with the exact right permissions (I guessed wrong twice)&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Dockerfile&lt;/code&gt; I maintained separately&lt;/li&gt;
&lt;li&gt;AWS credentials rotated manually every 90 days&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pipeline was the visible part. The invisible part was 3 days of setup I did 18 months ago that I could no longer remember well enough to recreate.&lt;/p&gt;

&lt;p&gt;When a new teammate joined and asked "how does deploy work?" — I sent them the workflow file and said "it's complicated."&lt;/p&gt;

&lt;p&gt;That's not an answer. That's a warning sign.&lt;/p&gt;

&lt;h2&gt;
  
  
  The breaking point
&lt;/h2&gt;

&lt;p&gt;In February, I switched from Node 18 to Node 20. The Docker build broke because my base image was pinned to &lt;code&gt;node:18-alpine&lt;/code&gt; in three different places — the Dockerfile, the Actions workflow, and a &lt;code&gt;.nvmrc&lt;/code&gt; file I had forgotten existed.&lt;/p&gt;

&lt;p&gt;The fix took 45 minutes. The error message was not helpful. I fixed it by diffing my Dockerfile against a Stack Overflow answer from 2023.&lt;/p&gt;

&lt;p&gt;Two weeks later, AWS deprecated the &lt;code&gt;amazon-ecs-render-task-definition@v1&lt;/code&gt; action. The pipeline broke silently — it ran, reported success, but the new image never actually deployed. I found out because a user filed a bug for something I had &lt;em&gt;definitely&lt;/em&gt; already fixed.&lt;/p&gt;

&lt;p&gt;That was the moment I decided: the pipeline is not worth maintaining.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tried first
&lt;/h2&gt;

&lt;p&gt;I looked at Render and Railway. Both are good products. Neither deploys into my own AWS account — they provision their own infrastructure. My company has a compliance requirement that customer data stays in a customer-owned AWS environment. So those were out.&lt;/p&gt;

&lt;p&gt;I looked at AWS CodePipeline. I wanted to solve complexity, not add more of it.&lt;/p&gt;

&lt;p&gt;Then a colleague mentioned &lt;a href="https://nexusai.run" rel="noopener noreferrer"&gt;NEXUS AI&lt;/a&gt;. He described it as "a CLI that handles all the ECS stuff so you don't have to." I was skeptical. That's what everyone says.&lt;/p&gt;

&lt;h2&gt;
  
  
  The initial deploy
&lt;/h2&gt;

&lt;p&gt;I installed the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @nexusai/cli
nexus login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I pointed it at my repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/myorg/my-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; aws_ecs_fargate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I expected this to fail immediately. My expectations for new DevOps tools are calibrated by years of experience.&lt;/p&gt;

&lt;p&gt;It didn't fail. Four and a half minutes later I got back a URL. The app was running. The same app. In my AWS account.&lt;/p&gt;

&lt;p&gt;I checked the AWS console out of habit. There was an ECS cluster. A task definition. A service. An ECR repository with the image in it. NEXUS AI had provisioned all of it.&lt;/p&gt;

&lt;p&gt;I had not written a Dockerfile. I had not configured any IAM roles. I had not touched the AWS console.&lt;/p&gt;

&lt;p&gt;I sat with that for a moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happens under the hood
&lt;/h2&gt;

&lt;p&gt;Here's what &lt;code&gt;nexus deploy source&lt;/code&gt; does, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reads your repo&lt;/strong&gt; — detects the runtime from &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;, &lt;code&gt;go.mod&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Builds the container&lt;/strong&gt; on NEXUS AI's build infrastructure — not your machine, not a GitHub runner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pushes the image&lt;/strong&gt; to an ECR repository it provisions in your account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creates (or updates) the ECS infrastructure&lt;/strong&gt; — cluster, task definition, service, load balancer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Issues a TLS certificate&lt;/strong&gt; via ACM and wires it to the load balancer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waits for health checks&lt;/strong&gt; to pass before returning the live URL&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps 3–5 are the 3 days of manual work I did 18 months ago. They now run in parallel and take about 3 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new GitHub Actions workflow
&lt;/h2&gt;

&lt;p&gt;Here's my deploy workflow today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Production&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nexus deploy redeploy --deployment-id ${{ secrets.NEXUSAI_DEPLOYMENT_ID }}&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;NEXUSAI_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.NEXUSAI_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;24 lines, including &lt;code&gt;name:&lt;/code&gt; fields and blank lines.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;deploy&lt;/code&gt; job has one step. It calls &lt;code&gt;nexus deploy redeploy&lt;/code&gt;, which tells NEXUS AI to rebuild from the latest commit and roll it out with a rolling update. No Docker commands. No AWS credentials. No ECR. No ECS task definition wrangling.&lt;/p&gt;

&lt;p&gt;I kept the &lt;code&gt;test&lt;/code&gt; job. NEXUS AI doesn't replace your test suite — it replaces everything &lt;em&gt;after&lt;/em&gt; tests pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secrets and environment variables
&lt;/h2&gt;

&lt;p&gt;Before, I had secrets in three places: GitHub Actions secrets (for the pipeline), AWS Secrets Manager (for the app), and a &lt;code&gt;.env.example&lt;/code&gt; file that was always slightly out of date.&lt;/p&gt;

&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus secret &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres://user:pass@host/db &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_live_... &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are encrypted at rest and injected as environment variables when the container starts. The pipeline only needs &lt;code&gt;NEXUSAI_TOKEN&lt;/code&gt; — one secret instead of seven.&lt;/p&gt;

&lt;p&gt;After updating secrets, one command applies them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy redeploy &lt;span class="nt"&gt;--deployment-id&lt;/span&gt; &amp;lt;your-deployment-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rollback
&lt;/h2&gt;

&lt;p&gt;Old workflow rollback: figure out the previous image SHA, manually update the ECS task definition, trigger a new deployment, hope the old image hasn't been cleaned up by the ECR lifecycle policy.&lt;/p&gt;

&lt;p&gt;New rollback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nexus deploy rollback &lt;span class="nt"&gt;--deployment-id&lt;/span&gt; &amp;lt;your-deployment-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reverts to the previous container image. Health checks run. Done. I've used this twice. Both times took under 90 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redeployment speed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;First deploy:&lt;/strong&gt; ~4.5 minutes (infrastructure provisioning included).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subsequent deploys:&lt;/strong&gt; 60–90 seconds. Infrastructure is already provisioned, so it's just build → push → rolling update.&lt;/p&gt;

&lt;p&gt;My old pipeline took 10–12 minutes. Most of that was the Docker build running on GitHub's shared runners plus the ECS service stability wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I lost
&lt;/h2&gt;

&lt;p&gt;Every tool has trade-offs. These are the real ones:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Less visibility into the build environment.&lt;/strong&gt; With a Dockerfile I wrote, I knew exactly what was in the image. With source-based deployment, NEXUS AI generates the image. You can inspect it — &lt;code&gt;nexus deploy logs&lt;/code&gt; gives the full build output — but you're not authoring the Dockerfile. For most apps this is fine. If you have specific system dependencies (custom C extensions, obscure shared libraries), test carefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first deploy takes time.&lt;/strong&gt; Infrastructure provisioning isn't instant. If you need sub-30-second cold deploys for some reason, this isn't that. But once infrastructure exists, redeployments are fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You're adding a dependency.&lt;/strong&gt; NEXUS AI is now in your deploy path. Worth knowing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Old workflow&lt;/th&gt;
&lt;th&gt;New workflow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lines of YAML&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline runtime&lt;/td&gt;
&lt;td&gt;10–12 min&lt;/td&gt;
&lt;td&gt;60–90 sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS console setup&lt;/td&gt;
&lt;td&gt;~3 days (one-time)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets locations&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback steps&lt;/td&gt;
&lt;td&gt;~6 manual steps&lt;/td&gt;
&lt;td&gt;1 command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Last random breakage&lt;/td&gt;
&lt;td&gt;November&lt;/td&gt;
&lt;td&gt;Hasn't happened&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @nexusai/cli

&lt;span class="c"&gt;# Authenticate&lt;/span&gt;
nexus login

&lt;span class="c"&gt;# First deploy — detects Node/Python/Go automatically, no Dockerfile needed&lt;/span&gt;
nexus deploy &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repo&lt;/span&gt; https://github.com/your/repo &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; my-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; aws_ecs_fargate   &lt;span class="c"&gt;# or gcp_cloud_run, azure_container_apps&lt;/span&gt;

&lt;span class="c"&gt;# Check status&lt;/span&gt;
nexus deploy status &lt;span class="nt"&gt;--deployment-id&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# Set environment variables&lt;/span&gt;
nexus secret &lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;value &lt;span class="nv"&gt;KEY2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;value2

&lt;span class="c"&gt;# Redeploy (use this in CI)&lt;/span&gt;
nexus deploy redeploy &lt;span class="nt"&gt;--deployment-id&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# Rollback&lt;/span&gt;
nexus deploy rollback &lt;span class="nt"&gt;--deployment-id&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For CI/CD: add &lt;code&gt;NEXUSAI_TOKEN&lt;/code&gt; and &lt;code&gt;NEXUSAI_DEPLOYMENT_ID&lt;/code&gt; as secrets in your GitHub repo settings, then replace your deploy steps with the one-liner from the workflow above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;The 87-line YAML file wasn't the real cost. The real cost was the cognitive overhead of owning it — the 45-minute debugging session when Node versions drifted, the silent failure when an Action was deprecated, the "it's complicated" I sent to a new teammate.&lt;/p&gt;

&lt;p&gt;I don't miss any of that.&lt;/p&gt;

&lt;p&gt;If you're maintaining a pipeline like the one I had, it's worth spending 20 minutes to find out how much of it you can delete.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Building something and want to compare notes? Drop it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
