<?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: Devanshukoli</title>
    <description>The latest articles on DEV Community by Devanshukoli (@devanshukoli).</description>
    <link>https://dev.to/devanshukoli</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%2F1022215%2F86f86362-dd99-483f-aafe-fb337fe533cc.png</url>
      <title>DEV Community: Devanshukoli</title>
      <link>https://dev.to/devanshukoli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devanshukoli"/>
    <language>en</language>
    <item>
      <title>I Had 48 Hours and a GitHub URL. Here's What Broke on the Way to Production.</title>
      <dc:creator>Devanshukoli</dc:creator>
      <pubDate>Sun, 09 Aug 2026 16:09:51 +0000</pubDate>
      <link>https://dev.to/devanshukoli/i-had-48-hours-and-a-github-url-heres-what-broke-on-the-way-to-production-3ho</link>
      <guid>https://dev.to/devanshukoli/i-had-48-hours-and-a-github-url-heres-what-broke-on-the-way-to-production-3ho</guid>
      <description>&lt;p&gt;The Zerops Challenge is simple on paper: 48 hours, build something, deploy it on Zerops, submit. What actually happens in those 48 hours is less simple. This is the honest version of mine — what I built, how I actually used AI while building it, and the three specific ways production said no before it said yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually built
&lt;/h2&gt;

&lt;p&gt;DevFlow takes a public GitHub repository URL and turns it into something you can actually explore instead of manually digging through. Paste a repo, and it clones it, figures out the languages, frameworks, dependencies, folder structure, and API routes, and turns all of that into a knowledge graph you can query — including asking it plain-English questions about the codebase, grounded in what it actually found, not just a model's general guess about what a typical repo looks like.&lt;/p&gt;

&lt;p&gt;The idea came from a problem I actually have: joining an unfamiliar codebase always means the same slow ritual — README, package.json, folder structure, entry point, routes, services, repeat until it clicks. DevFlow is my attempt at compressing that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pipeline:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub repo URL
      ↓
Analysis job queued
      ↓
Worker clones + inspects the repo
      ↓
Extract languages, frameworks, dependencies, API surface
      ↓
Project facts into a FalkorDB knowledge graph
      ↓
Explorable report + "Ask DevFlow" Q&amp;amp;A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three services, deployed on Zerops: the &lt;strong&gt;frontend&lt;/strong&gt;, the &lt;strong&gt;API&lt;/strong&gt;, and a &lt;strong&gt;worker&lt;/strong&gt; that pulls jobs off a queue and does the actual repo analysis in the background — so a big repo doesn't hang an HTTP request while it clones and inspects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I didn't just throw the repo at an LLM
&lt;/h2&gt;

&lt;p&gt;The lazy version of this idea is: clone repo, dump the files into a prompt, ask an LLM to explain it. I didn't want that, for one concrete reason — if you ask an LLM to "explain this architecture" with no grounding, you can't tell if the answer reflects the actual repo or the model's general assumptions about what repos like this usually look like.&lt;/p&gt;

&lt;p&gt;So the graph comes first. Facts get extracted deterministically — no LLM involved in deciding "this is a monorepo" or "this exposes a REST API" — and only once those facts exist does the AI layer get to answer questions, using the graph as its source of truth instead of its own memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I actually used AI Studio, honestly
&lt;/h2&gt;

&lt;p&gt;I used Google AI Studio during the build, mostly for prototyping speed. I want to be specific about what that means, because "I used AI" can mean wildly different things, and the Zerops Challenge rules require disclosing this properly anyway — I'd rather over-explain than have it look vague.&lt;/p&gt;

&lt;p&gt;I didn't ask it to build the app. I broke the project into individual pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a specific analysis step, &lt;/li&gt;
&lt;li&gt;a specific worker task, &lt;/li&gt;
&lt;li&gt;a specific piece of the graph pipeline &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and had AI Studio implement one bounded piece at a time. Every piece got checked against three things before I moved on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;did it build, &lt;/li&gt;
&lt;li&gt;did the tests pass, &lt;/li&gt;
&lt;li&gt;did it actually behave correctly when I ran it myself. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of those failed, I fixed it, or fed the failure back and re-tried. Nothing got accepted because it looked plausible — it got accepted because I ran it and watched it work.&lt;/p&gt;

&lt;p&gt;That distinction mattered more than usual on this project, because the parts that actually took real debugging time weren't things AI Studio touched at all — they showed up once the code hit Zerops in production, which is where prototyping speed stops mattering and the actual environment starts talking back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #1: Node said 20, pnpm wanted 22
&lt;/h2&gt;

&lt;p&gt;First deploy attempt on Zerops failed immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm 11.20.0
requires at least Node.js v22.13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Zerops environment was running Node 20. Straightforward once I saw it — pin the base image to Node 22 — but it's the kind of failure that only shows up once you leave your local machine, where whatever Node version happened to be installed just quietly worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #2: pnpm blocked its own dependencies
&lt;/h2&gt;

&lt;p&gt;Fixed the Node version, redeployed, hit a new wall:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERR_PNPM_IGNORED_BUILDS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;pnpm's newer dependency build-script approval model was silently refusing to run install scripts for a few packages. This was new to me — I didn't know pnpm distinguished between "installing a dependency" and "letting that dependency run its own build steps" until it stopped one of mine cold. Fix was to explicitly allow the specific build scripts instead of disabling the safety check outright.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure #3: it built, then it wouldn't start
&lt;/h2&gt;

&lt;p&gt;This is the one that actually took the longest to figure out, because the build succeeded. Green build, no errors, felt done. Then the process crashed on startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;TypeError [ERR_INVALID_ARG_TYPE]
The "path" argument must be of type string or an instance of URL. Received undefined
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traced back to &lt;code&gt;fileURLToPath(...)&lt;/code&gt; being called with something undefined — an ESM-related path resolution issue that only showed up at runtime, not at build time. Which is the actual lesson here: &lt;strong&gt;a successful build tells you the code compiles. It tells you nothing about whether the process survives being started.&lt;/strong&gt; Those are two different checks, and I'd been treating a green build like a finish line.&lt;/p&gt;

&lt;p&gt;The visible symptom downstream was a 502 — because the API process was crashing before it ever bound to a port, health checks failed, and Zerops had nothing to route traffic to. Debugging a 502 by looking at networking first would've been a waste of time here; the process was already dead before networking was even relevant.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I actually used Zerops
&lt;/h2&gt;

&lt;p&gt;Three services running: the frontend (static), the API, and the worker. The API and worker both needed to talk to Supabase for persisted analysis data and to FalkorDB for the graph layer, so getting service-to-service networking and environment variables right across all three was its own small project. The worker is what makes the async pipeline possible — repo analysis happens off the request thread entirely, so the frontend can show real job progress instead of a spinner that means nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually mattered
&lt;/h2&gt;

&lt;p&gt;Not the AI Studio prototyping speed, honestly, even though that helped. What mattered was the loop I used everywhere, on the app code and on the deploy config both: change something, run it for real, read what actually happened, fix the actual cause, repeat. AI Studio moved implementation faster. It didn't skip a single one of these three failures for me — I found all three by reading logs, not by asking a model what was probably wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;code&gt;https://github.com/Devanshukoli/devflow&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Live deployment:&lt;/strong&gt; &lt;code&gt;https://frontend-2d86.prg1.zerops.app/&lt;/code&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cloud</category>
      <category>devchallenge</category>
      <category>github</category>
    </item>
    <item>
      <title>My login endpoint had a 5.4 second P99. I was sure I knew why. I was wrong.</title>
      <dc:creator>Devanshukoli</dc:creator>
      <pubDate>Sat, 18 Jul 2026 16:06:19 +0000</pubDate>
      <link>https://dev.to/devanshukoli/my-login-endpoint-had-a-54-second-p99-i-was-sure-i-knew-why-i-was-wrong-4j6e</link>
      <guid>https://dev.to/devanshukoli/my-login-endpoint-had-a-54-second-p99-i-was-sure-i-knew-why-i-was-wrong-4j6e</guid>
      <description>&lt;p&gt;Found this completely by accident. I wasn't debugging anything, I was just poking around a SigNoz instance I'd self-hosted the night before, ahead of a hackathon build sprint. Opened the Service tab, and there it was.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;skillbridge-api&lt;/code&gt; — P99: &lt;strong&gt;5449.97ms&lt;/strong&gt;. Error rate: &lt;strong&gt;0.00%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Zero errors is the annoying part. Nothing crashed, nothing threw, nothing would ever show up in an alert (not that I have any set up yet, but you get the idea). The app was doing exactly what it was told to do. It just took 5.4 seconds to do it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnalmoyv350jbigqgzdwv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnalmoyv350jbigqgzdwv.png" alt="Signoz Service Tab" width="799" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quick context if you're new here: SkillBridge is my side project, ed-tech app, Node/Express backend, Supabase for the DB, React frontend. I wired up SigNoz mostly to see what an actual OpenTelemetry setup looks like on a real app instead of a toy example. Wasn't expecting to find a real bug on day one. Found one anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trace #1: the login flow
&lt;/h2&gt;

&lt;p&gt;Opened a trace for &lt;code&gt;/api/auth/login&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Login&lt;/code&gt; — 873.95ms&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Find User&lt;/code&gt; — 745.99ms

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;GET&lt;/code&gt; out to Supabase — 322.09ms, with &lt;code&gt;tls.connect&lt;/code&gt; / &lt;code&gt;tcp.connect&lt;/code&gt; / &lt;code&gt;dns.lookup&lt;/code&gt; nested inside it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Verify Password&lt;/code&gt; — 124.42ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fygs8g5uba4svni50x7ha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fygs8g5uba4svni50x7ha.png" alt="Signoz Trace Detail login trace id" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;124ms for bcrypt is fine, that's the whole point of bcrypt being slow. 746ms to fetch one user row is not fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gotcha that had nothing to do with the bug but still cost me 10 minutes
&lt;/h2&gt;

&lt;p&gt;Poking through other traces, I found a service literally named this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unknown_service:C:\Users\Devanshukoli\scoop\apps\nvm\current\nodejs\nodejs\node.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's what SigNoz falls back to when you forget to set &lt;code&gt;OTEL_SERVICE_NAME&lt;/code&gt;. It just uses the binary path instead. Not a big deal until you've got two or three scripts running and your service list turns into unreadable garbage. Fix is one line:&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;OTEL_SERVICE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;skillbridge-worker node script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mentioning it because nobody tells you this until you hit it yourself, and then it's obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual bug
&lt;/h2&gt;

&lt;p&gt;That exact "unknown_service" trace is where the real evidence was sitting, which I only noticed because I'd already opened it to laugh at the naming issue. Seven back-to-back &lt;code&gt;GET&lt;/code&gt; calls, each 300–600ms, none of them overlapping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;315.03ms
331.15ms
302.51ms
600.00ms
321.15ms
393.40ms
...
total: 2.52s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuld9a6dl0iwfg8kb0010.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuld9a6dl0iwfg8kb0010.png" alt="Signoz Trace Details" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seven round trips to the same downstream service, one after another. Not "one query is slow." Just a straight-up queue that nobody asked for.&lt;/p&gt;

&lt;h2&gt;
  
  
  My first guess (wrong)
&lt;/h2&gt;

&lt;p&gt;Staring at all those &lt;code&gt;tls.connect&lt;/code&gt; spans showing up over and over, I figured: we're probably spinning up a new Supabase client on every request, so we keep paying a fresh handshake each time.&lt;/p&gt;

&lt;p&gt;Reasonable guess. Took about a minute to check, and it died instantly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;supabaseInstance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SupabaseClient&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSupabaseClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;SupabaseClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabaseInstance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;supabaseInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;supabaseInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;anonKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;supabaseInstance&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;Already a singleton. My theory was just wrong, and I'm glad I checked the file instead of writing that guess down as fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually going on
&lt;/h2&gt;

&lt;p&gt;Found it in &lt;code&gt;supabaseGetCurriculum&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tracks&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_tracks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawModules&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order&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="na"&gt;ascending&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawLessons&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_lessons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order&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="na"&gt;ascending&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawProjects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_projects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;progressData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_progress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;submissionsData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_submissions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six queries. None of them need each other's result. All six waiting in line anyway, because that's just how it comes out when you're writing a function at 1am and not thinking about what actually depends on what.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tracks&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawModules&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawLessons&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawProjects&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;progressData&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;submissionsData&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_tracks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order&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="na"&gt;ascending&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="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_lessons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order&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="na"&gt;ascending&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="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_projects&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_progress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;skillbridge_submissions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&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;h2&gt;
  
  
  Where I have to be honest with you
&lt;/h2&gt;

&lt;p&gt;Ran it. First trace after the fix: 1.49s total, and two of the calls clearly ran at the same time, no repeated handshake between them. I was pretty happy about that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbs14m6o67nrsu3a7amra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbs14m6o67nrsu3a7amra.png" alt="Trace image" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ran the exact same endpoint again a few minutes later. 2.44s. Three separate calls, each one paying its own &lt;code&gt;tls.connect&lt;/code&gt; and &lt;code&gt;tcp.connect&lt;/code&gt; again, like nothing carried over from the last request at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8j0dvghyc010nvjkutvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8j0dvghyc010nvjkutvs.png" alt="Trace lookups" width="800" height="661"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same code path. Same endpoint. Two completely different results. I wanted to go check the Service tab and see if P99 had actually moved over the last hour, and make sure my dev server had actually restarted with the new code instead of me testing against a stale process. Then my laptop crashed. An hour before this was due.&lt;/p&gt;

&lt;p&gt;So that's where it ends for now. Not fixed-and-confirmed. Fixed-and-hopeful. Which, if I'm honest, is closer to how most of my debugging actually goes anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell past-me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Zero error rate doesn't mean zero problems. Nothing pages you for "technically correct but slow."&lt;/li&gt;
&lt;li&gt;Check your theory against the actual code before you say it out loud. My first guess sounded smart and was completely wrong.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Promise.all&lt;/code&gt; isn't magic, it just relocates the bottleneck. I've now got a single query sitting around 1s that I still need to look at.&lt;/li&gt;
&lt;li&gt;One good trace after a fix proves nothing on its own. Two traces disagreeing means you need the aggregate number, not another screenshot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building something and haven't wired up tracing yet, do it before you think you need it. I self-hosted &lt;a href="https://signoz.io/docs/" rel="noopener noreferrer"&gt;SigNoz&lt;/a&gt; for this, and it found me a bug I wasn't even looking for on day one. Probably will for you too.&lt;/p&gt;

</description>
      <category>signoz</category>
      <category>opentelemetry</category>
      <category>observability</category>
      <category>wemakedevs</category>
    </item>
  </channel>
</rss>
