<?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: Gabriel Menezes</title>
    <description>The latest articles on DEV Community by Gabriel Menezes (@mnzs).</description>
    <link>https://dev.to/mnzs</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%2F391416%2F9324fde2-488d-419f-a08b-122672063708.png</url>
      <title>DEV Community: Gabriel Menezes</title>
      <link>https://dev.to/mnzs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mnzs"/>
    <language>en</language>
    <item>
      <title>One MCP config for Claude Code, OpenCode and OMP</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Thu, 15 Oct 2026 03:29:23 +0000</pubDate>
      <link>https://dev.to/mnzs/one-mcp-config-for-claude-code-opencode-and-omp-eeb</link>
      <guid>https://dev.to/mnzs/one-mcp-config-for-claude-code-opencode-and-omp-eeb</guid>
      <description>&lt;h2&gt;
  
  
  Three files for one server
&lt;/h2&gt;

&lt;p&gt;You use Claude Code for one task and OpenCode for another, and both should see the same Figma and Linear MCP servers. Each harness wants them in its own file, under its own keys:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;harness&lt;/th&gt;
&lt;th&gt;file&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.mcp.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenCode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;opencode.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OMP&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.omp/mcp.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Writing three files once is tedious. Keeping them equal is the real cost: change a URL in one, forget the others, and half your sessions start without the server. Then each harness needs its own login.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the login breaks
&lt;/h2&gt;

&lt;p&gt;The files are the easy part. Authentication fails differently in each harness:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;server&lt;/th&gt;
&lt;th&gt;harness&lt;/th&gt;
&lt;th&gt;the harness's own login&lt;/th&gt;
&lt;th&gt;what &lt;code&gt;ivar mcp auth&lt;/code&gt; does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Figma&lt;/td&gt;
&lt;td&gt;OpenCode&lt;/td&gt;
&lt;td&gt;Figma refuses OpenCode's client registration; &lt;code&gt;opencode mcp auth&lt;/code&gt; prints &lt;code&gt;Authentication failed&lt;/code&gt; and exits 0&lt;/td&gt;
&lt;td&gt;registers a client under a name Figma accepts, runs the browser flow and writes the tokens into OpenCode's store&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Figma, Linear&lt;/td&gt;
&lt;td&gt;OMP&lt;/td&gt;
&lt;td&gt;OMP has no MCP login command&lt;/td&gt;
&lt;td&gt;runs the browser flow itself and imports the token with &lt;code&gt;omp auth-broker import&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Figma, Linear&lt;/td&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;claude mcp login&lt;/code&gt; works&lt;/td&gt;
&lt;td&gt;hands the browser step to &lt;code&gt;claude mcp login&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;OpenCode&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;opencode mcp auth&lt;/code&gt; works&lt;/td&gt;
&lt;td&gt;hands the browser step to &lt;code&gt;opencode mcp auth&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Where the harness's own login works, &lt;code&gt;ivar&lt;/code&gt; uses it. It only takes over where the harness cannot finish. &lt;a href="https://ivar.run/blog/figma-mcp-opencode?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;Figma MCP on OpenCode: fix "Authentication failed"&lt;/a&gt; explains the Figma case in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declare once
&lt;/h2&gt;

&lt;p&gt;Install &lt;code&gt;ivar&lt;/code&gt;, create a hall in an empty directory with the harnesses you use, and add the servers:&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; &lt;span class="s1"&gt;'https://ivar.run/install?ref=one-mcp-config'&lt;/span&gt; | sh
&lt;span class="nb"&gt;mkdir &lt;/span&gt;tools-hall &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;tools-hall
ivar init &lt;span class="nt"&gt;--provider&lt;/span&gt; claude-code
ivar provider add opencode
ivar provider add omp
ivar mcp add figma
ivar mcp add linear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;figma&lt;/code&gt; and &lt;code&gt;linear&lt;/code&gt; are known names, so &lt;code&gt;ivar mcp add&lt;/code&gt; fills in their URLs. Any other HTTP server takes &lt;code&gt;--url&lt;/code&gt;, for example &lt;code&gt;ivar mcp add sentry --url https://mcp.sentry.dev/mcp&lt;/code&gt;. Adding a server that is already declared the same way changes nothing; adding one with the same name and a different URL is refused instead of overwriting it.&lt;/p&gt;

&lt;p&gt;The declaration lives in the hall's &lt;code&gt;ivar.json&lt;/code&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;"mcp"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"figma"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&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://mcp.figma.com/mcp"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linear"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&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://mcp.linear.app/mcp"&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;&lt;code&gt;ivar mcp add&lt;/code&gt; writes each harness's file from it on the spot. After you edit &lt;code&gt;ivar.json&lt;/code&gt; by hand, &lt;code&gt;ivar sync&lt;/code&gt; rewrites the three files to match.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authenticate once per server
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar mcp auth figma &lt;span class="nt"&gt;--all-providers&lt;/span&gt;
ivar mcp auth linear &lt;span class="nt"&gt;--all-providers&lt;/span&gt;
ivar mcp status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--all-providers&lt;/code&gt; runs every harness the hall lists, one after the other, because each login takes over the terminal and waits on the browser. Every harness is attempted even if an earlier one fails, and the run is reported as needing attention when any of them does. When a client registration happens first, as with Figma on OpenCode, it is reported apart from the login: a registered client is not yet an authenticated one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ivar mcp status&lt;/code&gt; prints which server has credentials on which harness. The client secret lives in &lt;code&gt;.ivar/secrets/mcp.env&lt;/code&gt;, outside git. Tokens never go into &lt;code&gt;ivar.json&lt;/code&gt;, so you can commit the file and a teammate gets the same servers after their own &lt;code&gt;ivar mcp auth&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you need this?
&lt;/h2&gt;

&lt;p&gt;With one harness and a server whose login works there, no. Add the server to that harness's file and run its login. &lt;code&gt;ivar&lt;/code&gt; earns its place when you use more than one harness, when a team should share the same servers, or when the login fails, as it does for Figma on OpenCode and for any OAuth server on OMP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Three harnesses: Claude Code, OpenCode and OMP.&lt;/li&gt;
&lt;li&gt;macOS and Linux. Windows is not supported, and WSL is untested.&lt;/li&gt;
&lt;li&gt;HTTP MCP servers. Figma and Linear are the servers &lt;code&gt;ivar mcp auth&lt;/code&gt; has been run against. For another OAuth server, Claude Code and OpenCode use their own login and OMP uses the flow &lt;code&gt;ivar&lt;/code&gt; runs; whether that server accepts it is up to the server.&lt;/li&gt;
&lt;li&gt;The OAuth flow talks to each MCP server directly. &lt;code&gt;ivar&lt;/code&gt; has no server of its own in the middle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Then add your repos
&lt;/h2&gt;

&lt;p&gt;The hall that holds your MCP servers is also where &lt;code&gt;ivar&lt;/code&gt; mounts your repositories and runs a feature across them, with every session reading the same servers. The &lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; mounts the first repo. The &lt;a href="https://ivar.run/docs/guide/mcp?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;MCP guide&lt;/a&gt; covers transports and OAuth per harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/blog/figma-mcp-opencode?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;Figma MCP on OpenCode: fix "Authentication failed"&lt;/a&gt;: why Figma refuses OpenCode's registration and the four commands that fix it.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/docs/recipes/shared-mcp-servers?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;Declare MCP servers once for every harness&lt;/a&gt;: the short recipe.&lt;/li&gt;
&lt;li&gt;Harness pages: &lt;a href="https://ivar.run/docs/guide/mcp/providers/claude-code?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, &lt;a href="https://ivar.run/docs/guide/mcp/providers/opencode?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;OpenCode&lt;/a&gt;, &lt;a href="https://ivar.run/docs/guide/mcp/providers/omp?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-mcp-config-claude-code-opencode-omp" rel="noopener noreferrer"&gt;OMP&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>opencode</category>
      <category>devtools</category>
    </item>
    <item>
      <title>One repo, many agents: parallel features from a Figma prototype</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Wed, 30 Sep 2026 00:56:35 +0000</pubDate>
      <link>https://dev.to/mnzs/one-repo-many-agents-parallel-features-from-a-figma-prototype-2o41</link>
      <guid>https://dev.to/mnzs/one-repo-many-agents-parallel-features-from-a-figma-prototype-2o41</guid>
      <description>&lt;h2&gt;
  
  
  One repo, one big prototype
&lt;/h2&gt;

&lt;p&gt;Your designer hands over a Figma prototype with onboarding, checkout and a profile area. It all lands in one app repository. You want three agents working at once, one per area, and you want the result to arrive as a single pull request.&lt;/p&gt;

&lt;p&gt;Does &lt;code&gt;ivar&lt;/code&gt; make sense with one repo and many parallel branches, or only when work spans several repositories? It does, and this post walks through it end to end.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hall with one repo
&lt;/h2&gt;

&lt;p&gt;Create the hall as its own git repo, then add the app repository:&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;app-hall &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;app-hall &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git init
ivar init
ivar repo add app git@github.com:acme/app.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ivar init&lt;/code&gt; sets the hall up for Claude Code. For OpenCode or OMP, run&lt;br&gt;
&lt;code&gt;ivar init --provider opencode&lt;/code&gt; or &lt;code&gt;ivar init --provider omp&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;The Figma MCP server is declared once in &lt;code&gt;ivar.json&lt;/code&gt; and materialised into each session, so every agent you start can read the prototype. &lt;a href="https://ivar.run/blog/figma-mcp-opencode?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo" rel="noopener noreferrer"&gt;Configure Figma MCP for OpenCode in one step&lt;/a&gt; shows the block and the auth step, and the &lt;a href="https://ivar.run/docs/guide/mcp?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo" rel="noopener noreferrer"&gt;MCP guide&lt;/a&gt; covers the other harnesses.&lt;/p&gt;

&lt;p&gt;A fresh worktree is a clean checkout. Installed dependencies and generated code are not there. Put what a new worktree needs in a setup script at &lt;code&gt;.ivar/setups/app.sh&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="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
make deps
make codegen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ivar&lt;/code&gt; runs it with &lt;code&gt;bash&lt;/code&gt; inside the new worktree, and every branch you cut below runs it, so each agent starts from a working tree instead of a broken build. The &lt;a href="https://ivar.run/docs/guide/hall-upkeep?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo#author-a-setup-script" rel="noopener noreferrer"&gt;setup script guide&lt;/a&gt; lists the variables the script gets and has a Flutter version (&lt;code&gt;flutter pub get&lt;/code&gt;, &lt;code&gt;build_runner&lt;/code&gt;, &lt;code&gt;pod install&lt;/code&gt;, secrets).&lt;/p&gt;

&lt;h2&gt;
  
  
  A main feature and one subfeature per slice
&lt;/h2&gt;

&lt;p&gt;Create the main feature and promote the repo in it first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature create figma-proto
ivar feature promote figma-proto app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Order matters. A subfeature's branch is cut from its parent's branch, and that branch only exists once the parent has promoted the repo. If you promote a child first, &lt;code&gt;ivar&lt;/code&gt; asks to promote the parent for you, and without a terminal it refuses with the exact &lt;code&gt;ivar feature promote&lt;/code&gt; command to run — it never cuts the child from &lt;code&gt;main&lt;/code&gt; behind your back.&lt;/p&gt;

&lt;p&gt;Now add one subfeature per slice and promote the repo in each:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature create onboarding &lt;span class="nt"&gt;--parent&lt;/span&gt; figma-proto
ivar feature promote onboarding app
ivar feature create checkout &lt;span class="nt"&gt;--parent&lt;/span&gt; figma-proto
ivar feature promote checkout app
ivar feature create profile &lt;span class="nt"&gt;--parent&lt;/span&gt; figma-proto
ivar feature promote profile app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each child has its own branch and worktree, based on &lt;code&gt;figma-proto&lt;/code&gt;. The &lt;a href="https://ivar.run/docs/guide/features?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo#subfeatures" rel="noopener noreferrer"&gt;Subfeatures section of the features guide&lt;/a&gt; is the short reference for this flow.&lt;/p&gt;

&lt;p&gt;Before the children start, commit anything two of them would both edit on &lt;code&gt;figma-proto&lt;/code&gt;: new dependencies in &lt;code&gt;pubspec.yaml&lt;/code&gt; or &lt;code&gt;package.json&lt;/code&gt;, the route table, theme tokens. Each child then owns its own files, and integration has nothing to conflict on.&lt;/p&gt;

&lt;h2&gt;
  
  
  One agent per slice
&lt;/h2&gt;

&lt;p&gt;Open a session on the main feature and hand the split to &lt;code&gt;/ivar-subfeatures&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;ivar session start figma-proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/ivar-subfeatures figma-proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill creates and promotes the children if you have not, then writes each child's plan from its slice of the prototype: the screens it owns, the Figma frame links, the checks to run. It approves those plans and starts one detached session per child. For each child it prints the command that launches your harness in that session; paste each into its own terminal. In each child session, run &lt;code&gt;/ivar-execute&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each session works in its own worktree, so the agents never touch each other's files, index or &lt;code&gt;HEAD&lt;/code&gt;. Each session also gets the same harness config and the same MCP servers, Figma included.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watching the tree
&lt;/h2&gt;

&lt;p&gt;From any terminal, look at the whole tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature status figma-proto &lt;span class="nt"&gt;--recursive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After onboarding and checkout have been folded back, it 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;Subtree:
  figma-proto  state active  repos 1  blocked by: profile (active)
    checkout  state integrated  repos 1
    onboarding  state integrated  repos 1
    profile  state active  repos 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main feature lists the children that still block it. Once &lt;code&gt;profile&lt;/code&gt; is integrated, nothing does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Folding slices back
&lt;/h2&gt;

&lt;p&gt;When a child's run finishes, quit its harness so its session ends, then integrate it from the &lt;code&gt;figma-proto&lt;/code&gt; session. &lt;code&gt;/ivar-subfeatures&lt;/code&gt; does this for you as each child finishes; by hand it 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;ivar feature integrate onboarding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integration requires the child's plan gate to be approved, which the skill did when it wrote the plan. If you skip the skill, write the child's plan before you approve it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar plan create onboarding plan
ivar plan approve onboarding plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approving the empty scaffold passes the gate and gives the child's agent nothing to build. The child's work lands on the &lt;code&gt;figma-proto&lt;/code&gt; branch and the child closes as integrated. A merge conflict fails the command; fix it on the child's branch and run it again. Repeat for &lt;code&gt;checkout&lt;/code&gt; and &lt;code&gt;profile&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One pull request
&lt;/h2&gt;

&lt;p&gt;With every child integrated, the main feature carries all three slices. Preview the delivery first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature deliver figma-proto &lt;span class="nt"&gt;--preview&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The preview writes nothing. It reads the branch, the remote, the base and any existing pull request, and prints a fingerprint. When it looks right, apply it with the fingerprint the preview printed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature deliver figma-proto &lt;span class="nt"&gt;--fingerprint&lt;/span&gt; &amp;lt;fp&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That pushes the &lt;code&gt;figma-proto&lt;/code&gt; branch and opens one pull request against &lt;code&gt;main&lt;/code&gt;. Creating the pull request needs a GitHub remote; with a local remote, delivery only pushes. The &lt;a href="https://ivar.run/docs/guide/delivery?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo" rel="noopener noreferrer"&gt;delivery guide&lt;/a&gt; covers the details, including updating a pull request that already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you don't need ivar
&lt;/h2&gt;

&lt;p&gt;If you use one harness on one repo and never run work in parallel, you may not need any of this. Commit an &lt;code&gt;.mcp.json&lt;/code&gt; with the Figma server, use &lt;code&gt;git worktree add&lt;/code&gt; when you want a second branch checked out, and move on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ivar&lt;/code&gt; starts paying off when several agents run at once, possibly in different harnesses, and each needs the same MCP servers, the same setup script and an isolated worktree, with a way to fold the pieces back into one change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/blog/one-feature-across-multiple-repos?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo" rel="noopener noreferrer"&gt;One feature, three repos: a walkthrough&lt;/a&gt; — the multi-repo counterpart, with scope that grows mid-feature.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/docs/what-is-ivar?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo#who-its-for" rel="noopener noreferrer"&gt;Who ivar is for&lt;/a&gt; — single-repo parallel work and multi-repo work, side by side.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=parallel-features-single-repo" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt; — create a hall and your first feature.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>git</category>
      <category>figma</category>
      <category>devtools</category>
    </item>
    <item>
      <title>One feature, three repos: a walkthrough</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Wed, 30 Sep 2026 00:56:35 +0000</pubDate>
      <link>https://dev.to/mnzs/one-feature-three-repos-a-walkthrough-1e3l</link>
      <guid>https://dev.to/mnzs/one-feature-three-repos-a-walkthrough-1e3l</guid>
      <description>&lt;h2&gt;
  
  
  A field that crosses three repos
&lt;/h2&gt;

&lt;p&gt;You need to add a currency to invoices. The API has to store and return it, the web app has to show it, and somewhere in between a shared types package describes what an invoice looks like. Three repositories, one change.&lt;/p&gt;

&lt;p&gt;Why a single agent session across repos matters is covered in &lt;a href="https://ivar.run/blog/ai-coding-agent-multiple-repos?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-feature-across-multiple-repos" rel="noopener noreferrer"&gt;the context problem nobody solved&lt;/a&gt;. This post is the practical side: the commands, in order, for one feature that touches all three.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hall
&lt;/h2&gt;

&lt;p&gt;Create the hall as its own git repo and register the three repositories in it:&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;acme-hall &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;acme-hall &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git init
ivar init
ivar repo add api git@github.com:acme/api.git
ivar repo add web git@github.com:acme/web.git
ivar repo add types git@github.com:acme/types.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each one lands in &lt;code&gt;ivar.json&lt;/code&gt; under &lt;code&gt;repos&lt;/code&gt;. That file is the hall's manifest: which repos exist, where they come from, which harnesses and MCP servers every session gets. Nothing is promoted yet, so every repo sits on its default branch, read-only.&lt;/p&gt;

&lt;h2&gt;
  
  
  One feature, two repos to start
&lt;/h2&gt;

&lt;p&gt;Create the feature and promote the two repos you know you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature create billing-currency
ivar feature promote billing-currency api
ivar feature promote billing-currency web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Promoting a repo cuts a &lt;code&gt;billing-currency&lt;/code&gt; branch in it and gives it a worktree the feature can write to. &lt;code&gt;types&lt;/code&gt; stays on its default branch as read-only context.&lt;/p&gt;

&lt;p&gt;Start a session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar session start billing-currency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One session sees both promoted repos side by side, plus &lt;code&gt;types&lt;/code&gt; as read-only. The agent can change the API handler and the web component in the same conversation, and it can read the shared types to see what an invoice looks like today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope grows mid-way
&lt;/h2&gt;

&lt;p&gt;Halfway through, the agent reports the obvious: the invoice type lives in &lt;code&gt;types&lt;/code&gt;, and both the API and the web app import it. The currency field has to go there first, or the other two changes won't compile against each other.&lt;/p&gt;

&lt;p&gt;You don't need to stop the session or start over. From another terminal, promote the third repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature promote billing-currency types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;types&lt;/code&gt; gets its own &lt;code&gt;billing-currency&lt;/code&gt; branch and worktree, and the session can now write to it. The agent adds the field to the shared type and carries on with the API and the web app. The &lt;a href="https://ivar.run/docs/guide/features?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-feature-across-multiple-repos" rel="noopener noreferrer"&gt;features guide&lt;/a&gt; covers promotion in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where things stand
&lt;/h2&gt;

&lt;p&gt;Check the feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature status billing-currency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature `billing-currency` (branch: billing-currency):
  api  ready  worktree present  base: main
  types  ready  worktree present  base: main
  web  ready  worktree present  base: main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three repos, one branch name, each based on its own &lt;code&gt;main&lt;/code&gt;. No list of branches to keep in your head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delivering together
&lt;/h2&gt;

&lt;p&gt;When the work is done, preview the delivery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature deliver billing-currency &lt;span class="nt"&gt;--preview&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The preview writes nothing. For each promoted repo it reads the branch, the remote, the base and any existing pull request, then computes one fingerprint over all three. If any repo changes after you read the preview, the fingerprint no longer matches and apply refuses.&lt;/p&gt;

&lt;p&gt;Apply it with the fingerprint the preview printed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar feature deliver billing-currency &lt;span class="nt"&gt;--fingerprint&lt;/span&gt; &amp;lt;fp&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That pushes the &lt;code&gt;billing-currency&lt;/code&gt; branch in each repo and opens the three pull requests together, each with a comment linking its siblings, so a reviewer on the web PR can find the API and types PRs.&lt;/p&gt;

&lt;p&gt;Creating pull requests needs GitHub remotes. With local remotes, delivery only pushes. The &lt;a href="https://ivar.run/docs/guide/delivery?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-feature-across-multiple-repos" rel="noopener noreferrer"&gt;delivery guide&lt;/a&gt; covers updating existing pull requests and delivering a subset of repos with &lt;code&gt;--only&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you didn't do
&lt;/h2&gt;

&lt;p&gt;Cloning, branching, cross-linking pull requests and re-explaining context to fresh sessions were all handled by the feature, including when the scope grew mid-way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/blog/parallel-features-single-repo?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-feature-across-multiple-repos" rel="noopener noreferrer"&gt;One repo, many agents: parallel features from a Figma prototype&lt;/a&gt; — the single-repo counterpart, with subfeatures and one pull request.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/docs/guide/mcp?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-feature-across-multiple-repos" rel="noopener noreferrer"&gt;MCP servers in a hall&lt;/a&gt; — declare MCP servers once and every session across the three repos gets them.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=one-feature-across-multiple-repos" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt; — create a hall and your first feature.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>git</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Git worktrees are great. They stop at the repo boundary.</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:15:37 +0000</pubDate>
      <link>https://dev.to/mnzs/git-worktrees-are-great-they-stop-at-the-repo-boundary-4b9h</link>
      <guid>https://dev.to/mnzs/git-worktrees-are-great-they-stop-at-the-repo-boundary-4b9h</guid>
      <description>&lt;h2&gt;
  
  
  What the worktree posts get right
&lt;/h2&gt;

&lt;p&gt;Git worktrees (&lt;code&gt;git worktree add&lt;/code&gt;) have become an indispensable primitive in modern software engineering and agentic workflows. Most community articles explaining how to use git worktrees for AI coding agents get the core single-repository mechanics completely right:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Zero Stash and Context Switch Overhead&lt;/strong&gt;: You can launch an agentic session on an isolated feature branch without stashing uncommitted local work or altering your active working directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Object Database&lt;/strong&gt;: Worktrees share the parent repository's &lt;code&gt;.git&lt;/code&gt; object store. Creating a worktree takes milliseconds because Git simply writes a lightweight &lt;code&gt;.git&lt;/code&gt; text file pointing to &lt;code&gt;.git/worktrees/&amp;lt;id&amp;gt;&lt;/code&gt; in the main repository, avoiding the disk and network overhead of cloning full repository copies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent Index Files&lt;/strong&gt;: Each worktree maintains its own independent staging area (&lt;code&gt;index&lt;/code&gt;), &lt;code&gt;HEAD&lt;/code&gt; ref pointer, and reflog. This allows multiple agent sessions to run in parallel on different feature branches without encountering lock contention or file collision.&lt;/li&gt;
&lt;/ol&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%2F1nw8mifwzthl87nusyg2.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%2F1nw8mifwzthl87nusyg2.png" alt="Two worktrees of one repository share a single object store. A second repository has its own store, and no worktree command spans both." width="799" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The shared object store is what makes a worktree cheap, and it is also what makes it stop at the repository it belongs to.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For single-repository engineering, git worktrees provide an ideal local execution environment. The agent operates inside an isolated file tree, language servers index files correctly, build tools run natively, and git status tracks changes cleanly.&lt;/p&gt;

&lt;p&gt;However, modern software applications rarely reside in a single repository. The moment a software feature spans multiple repositories, the single-repo worktree model encounters a hard structural boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three-repo change
&lt;/h2&gt;

&lt;p&gt;Consider a routine architectural task in a polyrepo ecosystem: modifying an API contract. The feature spans three distinct git repositories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;api-service&lt;/code&gt;: The Rust backend implementing the updated endpoint payload.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;web-frontend&lt;/code&gt;: The TypeScript application consuming the API response.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs-site&lt;/code&gt;: The documentation repository hosting public API reference specs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To execute this change with an AI coding agent, you require a composite workspace configuration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Active edit capability on branch &lt;code&gt;feature-auth&lt;/code&gt; inside &lt;code&gt;api-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Active edit capability on branch &lt;code&gt;feature-auth&lt;/code&gt; inside &lt;code&gt;web-frontend&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Read-only reference access on default branch &lt;code&gt;main&lt;/code&gt; inside &lt;code&gt;docs-site&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using raw &lt;code&gt;git worktree&lt;/code&gt; commands manually requires executing a tedious multi-step sequence across three separate repository paths:&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;# Manual worktree creation across three repos&lt;/span&gt;
git &lt;span class="nt"&gt;-C&lt;/span&gt; ~/repos/api-service worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature-auth ../worktrees/api-feature-auth
git &lt;span class="nt"&gt;-C&lt;/span&gt; ~/repos/web-frontend worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature-auth ../worktrees/web-feature-auth
git &lt;span class="nt"&gt;-C&lt;/span&gt; ~/repos/docs-site worktree add ../worktrees/docs-main main

&lt;span class="c"&gt;# Create a temporary workspace directory and symlink worktrees&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/workspaces/feature-auth
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; ~/worktrees/api-feature-auth ~/workspaces/feature-auth/api
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; ~/worktrees/web-feature-auth ~/workspaces/feature-auth/web
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; ~/worktrees/docs-main ~/workspaces/feature-auth/docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executing these steps manually for every feature task is slow, repetitive, and error-prone. Consequently, developers build shell scripts to automate multi-repository worktree assembly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the script anyway
&lt;/h2&gt;

&lt;p&gt;Here is a typical, 60-line bash script that developers construct to automate multi-repository worktree setup for AI agent sessions:&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;FEATURE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FEATURE_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: Feature name required."&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;feature-name&amp;gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;WORKSPACE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.workspaces/&lt;/span&gt;&lt;span class="nv"&gt;$FEATURE_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WORKSPACE_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nv"&gt;REPOS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"api"&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/repos/api-service"&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"web"&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/repos/web-frontend"&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"docs"&lt;/span&gt;&lt;span class="o"&gt;]=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/repos/docs-site"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Initializing multi-repo worktrees for feature: &lt;/span&gt;&lt;span class="nv"&gt;$FEATURE_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;NAME &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!REPOS[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;REPO_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REPOS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;TARGET_WORKTREE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO_PATH&lt;/span&gt;&lt;span class="s2"&gt;/../worktrees/&lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;$FEATURE_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"docs"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# Read-only reference repository stays checked out on main&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating reference worktree for &lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt; on main..."&lt;/span&gt;
    git &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; worktree add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_WORKTREE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; main 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="c"&gt;# Feature repositories check out feature branch&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating feature worktree for &lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt; on branch &lt;/span&gt;&lt;span class="nv"&gt;$FEATURE_NAME&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    git &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FEATURE_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_WORKTREE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="c"&gt;# Symlink worktree into unified workspace folder&lt;/span&gt;
  &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sfn&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_WORKTREE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WORKSPACE_DIR&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Create combined harness instructions&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt; "&lt;/span&gt;&lt;span class="nv"&gt;$WORKSPACE_DIR&lt;/span&gt;&lt;span class="sh"&gt;/CLAUDE.md"
# Multi-Repo Workspace Context: &lt;/span&gt;&lt;span class="nv"&gt;$FEATURE_NAME&lt;/span&gt;&lt;span class="sh"&gt;
- api/: Rust backend service (editable feature worktree)
- web/: TypeScript web application (editable feature worktree)
- docs/: Documentation site (reference context only, DO NOT EDIT)
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Multi-repo workspace materialized at: &lt;/span&gt;&lt;span class="nv"&gt;$WORKSPACE_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WORKSPACE_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script automates worktree creation, symlinks the directories into a unified workspace folder, generates a basic &lt;code&gt;CLAUDE.md&lt;/code&gt;, and launches the agent harness. &lt;/p&gt;

&lt;p&gt;While this script works for basic local demos, attempting to rely on it in production engineering environments reveals four fundamental limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four things the script can't do
&lt;/h2&gt;

&lt;p&gt;While an ad-hoc shell script automates directory symlinking, it lacks the technical infrastructure required for reliable, safe multi-repository agent execution.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What it needs to do&lt;/th&gt;
&lt;th&gt;What the script does instead&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Guard writes to reference repos&lt;/td&gt;
&lt;td&gt;Relies on a soft prompt rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keep branches and lifecycle aligned&lt;/td&gt;
&lt;td&gt;Leaves dirty and orphaned trees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Materialise instructions&lt;/td&gt;
&lt;td&gt;Dirties tracked files in each repo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deliver the feature&lt;/td&gt;
&lt;td&gt;Pushes each branch on its own&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1. POSIX Filesystem Write Protection
&lt;/h3&gt;

&lt;p&gt;The shell script creates worktrees on disk using standard user write permissions (&lt;code&gt;0755&lt;/code&gt;/&lt;code&gt;0644&lt;/code&gt;). To restrict modifications in &lt;code&gt;docs/&lt;/code&gt;, the script relies exclusively on a text instruction inside &lt;code&gt;CLAUDE.md&lt;/code&gt;: &lt;code&gt;"docs/: reference context only, DO NOT EDIT"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Under high context load or multi-step reasoning tasks, language models non-deterministically violate prompt instructions. An agent fixing a broken build or lint error will edit files in &lt;code&gt;docs/&lt;/code&gt; directly, mutating git state in a reference repository. The script cannot enforce write restrictions at the operating system layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Session Lifecycle and Branch Alignment
&lt;/h3&gt;

&lt;p&gt;When an agent session finishes or crashes, the script leaves active worktrees and branches dangling across multiple repository directories. If a session fails midway:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Worktree lock references persist inside &lt;code&gt;.git/worktrees/&lt;/code&gt; across individual repos.&lt;/li&gt;
&lt;li&gt;Re-running the script throws errors because branches or worktree paths already exist.&lt;/li&gt;
&lt;li&gt;Developers must manually navigate to each repo directory to run &lt;code&gt;git worktree prune&lt;/code&gt; and delete orphaned feature branches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Furthermore, if branch creation fails in one repository (e.g., due to an uncommitted conflict on &lt;code&gt;main&lt;/code&gt;), the script leaves the workspace in a partially initialized, inconsistent state across repos without atomic rollback.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Clean Instruction Materialization
&lt;/h3&gt;

&lt;p&gt;The script injects instructions by writing a static &lt;code&gt;CLAUDE.md&lt;/code&gt; file at the root of the workspace. However, real-world repositories already contain their own provider-native instruction files (e.g., &lt;code&gt;api/CLAUDE.md&lt;/code&gt; and &lt;code&gt;web/CLAUDE.md&lt;/code&gt;). The script cannot merge or synthesize instructions across repositories.&lt;/p&gt;

&lt;p&gt;If the script writes instruction files directly inside individual repository worktrees, it leaves untracked, dirty files in git status that risk being accidentally committed by the agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Multi-Repo Feature Delivery
&lt;/h3&gt;

&lt;p&gt;Once an agent completes changes across &lt;code&gt;api/&lt;/code&gt; and &lt;code&gt;web/&lt;/code&gt;, delivering the feature requires verifying status, pushing feature branches across multiple repositories, and establishing cross-repository pull request references.&lt;/p&gt;

&lt;p&gt;The shell script leaves delivery entirely to manual git operations. It cannot verify atomic feature readiness across mounted repositories, track which repositories were actually modified during the session, or trigger synchronized multi-repo branch pushes (&lt;code&gt;deliver&lt;/code&gt;). Note that multi-repo delivery coordinates push operations across repositories, rather than attempting complex dependency sorting or automated merge ordering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guarding writes with chmod, not with a prompt
&lt;/h2&gt;

&lt;p&gt;The central vulnerability of custom multi-repo worktree scripts is relying on LLM prompt compliance for write protection. Soft prompt instructions and software hooks inevitably fail under context saturation, complex agent reasoning, or raw shell command execution.&lt;/p&gt;

&lt;p&gt;Robust write protection requires enforcing file immutability at the operating system layer using POSIX file permission masks (&lt;code&gt;chmod&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;0o222&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;chmod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;0o222&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;In an orchestrated View Directory architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Unpromoted Context Worktrees&lt;/strong&gt;: When a reference repository (such as &lt;code&gt;docs/&lt;/code&gt;) is mounted into the session workspace, write bits (&lt;code&gt;0o222&lt;/code&gt;) are stripped recursively across its worktree files and directories via &lt;code&gt;clear_write_bits&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic Kernel Enforcement&lt;/strong&gt;: If an agent attempts to modify a file inside an unpromoted repository—whether using a file edit tool, a bash output redirection (&lt;code&gt;&amp;gt;&lt;/code&gt;), or an automated code modifier—the operating system kernel rejects the write operation immediately with an &lt;code&gt;EACCES&lt;/code&gt; (Permission Denied) error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promoted Worktrees&lt;/strong&gt;: Repositories explicitly designated for active editing have write permissions restored (&lt;code&gt;u+w&lt;/code&gt;) via &lt;code&gt;restore_write_bits&lt;/code&gt; (&lt;code&gt;mode | 0o200&lt;/code&gt;), permitting authorized modifications:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;chmod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0o200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By operating at the kernel permission layer, write enforcement remains absolute regardless of LLM prompt drift, context saturation, or tool execution style.&lt;/p&gt;

&lt;p&gt;Git worktrees provide the essential foundation for local agent workspaces, but scaling them across multiple repositories requires dedicated session orchestration rather than fragile shell scripts. How a View Dir combines those worktrees with a kernel-enforced write guard is covered in &lt;a href="https://ivar.run/docs/what-is-ivar?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=git-worktree-multiple-repositories" rel="noopener noreferrer"&gt;what a View Dir is&lt;/a&gt;, and the &lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=git-worktree-multiple-repositories" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; walks through mounting your first one.&lt;/p&gt;

</description>
      <category>git</category>
      <category>ai</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How ivar helps non-technical teams work across multiple repos</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:15:06 +0000</pubDate>
      <link>https://dev.to/mnzs/how-ivar-helps-non-technical-teams-work-across-multiple-repos-2671</link>
      <guid>https://dev.to/mnzs/how-ivar-helps-non-technical-teams-work-across-multiple-repos-2671</guid>
      <description>&lt;h2&gt;
  
  
  Why this matters if you don't code
&lt;/h2&gt;

&lt;p&gt;You asked a simple question in Slack: "How does the login flow work today?" Two hours later, you received links to three different repositories, a recently merged PR, and an outdated API contract.&lt;/p&gt;

&lt;p&gt;Developers use AI agents to debug code. Product managers and tech leads can use them to debug &lt;em&gt;context&lt;/em&gt;, and &lt;code&gt;ivar&lt;/code&gt; sets that up with a few terminal commands you run once.&lt;/p&gt;

&lt;p&gt;If you are a product manager, a designer, a tech lead, or anyone who works &lt;em&gt;around&lt;/em&gt; a codebase rather than &lt;em&gt;inside&lt;/em&gt; it, you probably hit the same wall: the engineering team maintains five repositories, and you have no single place to understand what lives where, how things connect, or what changed.&lt;/p&gt;

&lt;p&gt;Ivar does not require you to write code. It gives you a structured view of a multi-repo codebase that an AI agent can reason over — and that means you can ask questions in plain language and get structured answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hall: one place for everything
&lt;/h2&gt;

&lt;p&gt;When an engineering team adopts ivar, they create a &lt;strong&gt;Hall&lt;/strong&gt; — a single directory that describes every repository the project depends on, which branch to use, and what instruction files carry the team's conventions.&lt;/p&gt;

&lt;p&gt;Think of the Hall as a table of contents for the codebase. It lists each repository by name, points at the right branch, and records the relationships between them. You do not need to know the file structure of five separate repos, or clone them one by one.&lt;/p&gt;

&lt;p&gt;The Hall is a file, and it lives in version control. If the team adds a repository, the Hall changes. If a repository is renamed or removed, the Hall changes. The Hall &lt;em&gt;is&lt;/em&gt; the source of truth for how the codebase is organised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asking questions about the codebase
&lt;/h2&gt;

&lt;p&gt;Once the Hall exists, ivar creates a &lt;strong&gt;view directory&lt;/strong&gt; — a single workspace that contains every repository on the right branch, with the agent's instruction files already set up. An AI agent opened in that directory can read across all the repositories at once.&lt;/p&gt;

&lt;p&gt;This is where you benefit without writing code. You can ask the agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What does the API contract look like for the billing feature?" — the agent reads the OpenAPI spec in one repo and can show you the current state.&lt;/li&gt;
&lt;li&gt;"Which repos were changed in the last feature delivery?" — the agent sees the git history across all the repos in the view directory.&lt;/li&gt;
&lt;li&gt;"What's the relationship between the frontend component and the backend endpoint it calls?" — the agent can trace the connection across repos.&lt;/li&gt;
&lt;li&gt;"Run the analysis and show me a report of what changed this week" — the agent executes the analysis tools already configured in the Hall.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are not reading source code. You are having a conversation with an agent that has read access to everything, and the agent translates the technical details into language you can act on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting insights without engineering time
&lt;/h2&gt;

&lt;p&gt;The typical alternative is asking an engineer to write a summary, run a report, or explain a dependency graph. That is expensive, slow, and stale the moment it is delivered.&lt;/p&gt;

&lt;p&gt;With ivar, the agent in the view directory can generate that summary on demand. The Hall already carries the context — which repos exist, how they relate, what the team's conventions are. The agent does not need to be re-introduced to the codebase every time.&lt;/p&gt;

&lt;p&gt;This is particularly useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sprint planning&lt;/strong&gt;: Ask the agent what changed in the last week and which areas of the codebase are active.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency reviews&lt;/strong&gt;: Ask the agent to trace how a change in one repo affects the others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Onboarding&lt;/strong&gt;: A new team member can ask the agent to explain the project structure, and the agent answers from the Hall's perspective rather than guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging in production&lt;/strong&gt;: When something breaks, you can ask the agent to look at the recent changes across all repos and identify what might have caused it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What ivar does not do
&lt;/h2&gt;

&lt;p&gt;Ivar does not replace your project management tool, your CI pipeline, or your engineering team. It is a local tool that gives an AI agent the context it needs to answer questions about a multi-repo codebase. The agent does the reasoning; the Hall provides the structure.&lt;/p&gt;

&lt;p&gt;Ivar also does not discover repos automatically. The engineering team defines the Hall: which repos, which branches, which instruction files. Once that is set, everyone on the team can use it.&lt;/p&gt;

&lt;p&gt;It does not remove the terminal either. &lt;code&gt;ivar&lt;/code&gt; is a command-line tool, and the agents it works with (Claude Code, OpenCode, OMP) run in a terminal. On Linux or macOS you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;ivar&lt;/code&gt; (&lt;code&gt;curl -fsSL https://ivar.run/install | sh&lt;/code&gt;) and, for GitHub repos, log in with &lt;code&gt;gh auth login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Clone the Hall and let ivar fetch its repos: &lt;code&gt;git clone &amp;lt;hall-url&amp;gt; team-hall&lt;/code&gt;, then &lt;code&gt;cd team-hall&lt;/code&gt; and &lt;code&gt;ivar sync&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Launch your agent in that directory (for example &lt;code&gt;claude&lt;/code&gt;) and type &lt;code&gt;/ivar-discovery&lt;/code&gt;. From there you ask questions in plain language; discovery only reads the code, so you cannot break anything.&lt;/li&gt;
&lt;li&gt;Before a new round of questions, run &lt;code&gt;ivar repo pull&lt;/code&gt; so the agent reads the latest code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An engineer can walk you through it in about fifteen minutes. After that, the terminal is the window you type your questions into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;If your engineering team already uses ivar, ask them for the Hall's git URL and for fifteen minutes to run the four steps above with you. The Hall's &lt;code&gt;ivar.json&lt;/code&gt; is a small file, and reading it gives you the vocabulary to ask the agent useful questions.&lt;/p&gt;

&lt;p&gt;If your team does not use ivar yet, the &lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ivar-non-technical-workflow" rel="noopener noreferrer"&gt;quickstart guide&lt;/a&gt; shows an engineer how to create a Hall. Setting up the Hall itself takes about fifteen minutes, and the return is a single place where everyone on the team, technical or not, can understand how the codebase is organised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/blog/ai-coding-agent-multiple-repos?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ivar-non-technical-workflow" rel="noopener noreferrer"&gt;The context problem nobody solved: AI agents across multiple repos&lt;/a&gt; — the technical foundation that makes a multi-repo view directory possible.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>devtools</category>
      <category>git</category>
    </item>
    <item>
      <title>Figma MCP on OpenCode: fix "Authentication failed"</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:15:05 +0000</pubDate>
      <link>https://dev.to/mnzs/configure-figma-mcp-for-opencode-in-one-step-1633</link>
      <guid>https://dev.to/mnzs/configure-figma-mcp-for-opencode-in-one-step-1633</guid>
      <description>&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;You add the Figma MCP server to &lt;code&gt;opencode.json&lt;/code&gt; and run &lt;code&gt;opencode mcp auth figma&lt;/code&gt;. No browser opens. OpenCode prints &lt;code&gt;Authentication failed&lt;/code&gt; and exits with status 0, so a script that checks the exit code thinks it worked. The agent then starts without Figma.&lt;/p&gt;

&lt;p&gt;Reinstalling OpenCode does not change it, and neither does a new Figma token. The failure happens before any token exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it fails
&lt;/h2&gt;

&lt;p&gt;MCP servers that use OAuth let a client register itself on the fly, with dynamic client registration. Figma's registration endpoint, &lt;code&gt;https://api.figma.com/v1/oauth/mcp/register&lt;/code&gt;, only accepts a short allowlist of client names. OpenCode registers under its own name, which is not on the list, so Figma refuses the registration and OpenCode never gets as far as the browser.&lt;/p&gt;

&lt;p&gt;Figma's documentation describes the workaround: register a client ahead of time under a name the allowlist accepts, then run the authorization flow with that client. Doing it by hand means a &lt;code&gt;curl&lt;/code&gt; to the registration endpoint, a PKCE flow with a local redirect, and writing the tokens where OpenCode reads them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix in four commands
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ivar&lt;/code&gt; does those steps for you. Install it, create a hall in an empty directory, declare Figma and authenticate:&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; &lt;span class="s1"&gt;'https://ivar.run/install?ref=figma-mcp-opencode'&lt;/span&gt; | sh
&lt;span class="nb"&gt;mkdir &lt;/span&gt;design-hall &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;design-hall
ivar init &lt;span class="nt"&gt;--provider&lt;/span&gt; opencode
ivar mcp add figma
ivar mcp auth figma &lt;span class="nt"&gt;--provider&lt;/span&gt; opencode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ivar mcp add figma&lt;/code&gt; writes the server into the hall's &lt;code&gt;ivar.json&lt;/code&gt; and into the &lt;code&gt;opencode.json&lt;/code&gt; next to it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ivar.json&lt;/code&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;"mcp"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"figma"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&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://mcp.figma.com/mcp"&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;&lt;code&gt;ivar mcp auth&lt;/code&gt; then pre-registers a client for OpenCode under a name Figma accepts, opens the browser for the authorization, listens for the redirect on &lt;code&gt;127.0.0.1:19876&lt;/code&gt;, and writes the tokens into OpenCode's MCP auth store. It reads the store back afterwards, so a run that leaves no tokens is reported as a failure instead of a silent exit 0. Start &lt;code&gt;opencode&lt;/code&gt; from the hall directory and the Figma tools are there.&lt;/p&gt;

&lt;p&gt;The client secret goes to &lt;code&gt;.ivar/secrets/mcp.env&lt;/code&gt;, which stays out of git. Tokens never go into &lt;code&gt;ivar.json&lt;/code&gt;, so the file is safe to commit and share.&lt;/p&gt;

&lt;p&gt;If Figma changes its allowlist, the registration step answers 403. That is the one place to look, and the error says so.&lt;/p&gt;

&lt;h2&gt;
  
  
  The next server, the next harness
&lt;/h2&gt;

&lt;p&gt;The same two commands work for other servers. &lt;code&gt;ivar mcp add linear&lt;/code&gt; declares Linear's MCP server; OpenCode's own login works for Linear, so &lt;code&gt;ivar mcp auth linear --provider opencode&lt;/code&gt; hands the browser step to &lt;code&gt;opencode mcp auth&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Other harnesses read the same declaration. Add Claude Code or OMP to the hall and authenticate every provider it lists, one at a time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar provider add claude-code
ivar &lt;span class="nb"&gt;sync
&lt;/span&gt;ivar mcp auth figma &lt;span class="nt"&gt;--all-providers&lt;/span&gt;
ivar mcp status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ivar provider add&lt;/code&gt; only records the harness; &lt;code&gt;ivar sync&lt;/code&gt; writes its MCP file from the same &lt;code&gt;ivar.json&lt;/code&gt;. Claude Code's own &lt;code&gt;claude mcp login&lt;/code&gt; works with Figma, so &lt;code&gt;ivar&lt;/code&gt; delegates to it. OMP has no MCP login command, so &lt;code&gt;ivar&lt;/code&gt; runs the flow itself and imports the token with &lt;code&gt;omp auth-broker import&lt;/code&gt;. &lt;code&gt;ivar mcp status&lt;/code&gt; shows which server has credentials on which provider. &lt;a href="https://ivar.run/blog/one-mcp-config-claude-code-opencode-omp?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=figma-mcp-opencode" rel="noopener noreferrer"&gt;One MCP config for Claude Code, OpenCode and OMP&lt;/a&gt; walks through all three harnesses side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then mount your repos
&lt;/h2&gt;

&lt;p&gt;The hall you created is the same hall &lt;code&gt;ivar&lt;/code&gt; uses to run agents across repositories. Mount the repos your design work lands in, start a session, and every session gets Figma from the same &lt;code&gt;ivar.json&lt;/code&gt;, on every branch and worktree, without another login. The &lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=figma-mcp-opencode" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; takes it from here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you need this?
&lt;/h2&gt;

&lt;p&gt;If you use only Claude Code, its own Figma login works and you do not need &lt;code&gt;ivar&lt;/code&gt; for this. The failure above is specific to Figma's allowlist and to harnesses that register under a name Figma does not accept: OpenCode today, and OMP, which has no MCP login of its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ivar&lt;/code&gt; supports three harnesses: Claude Code, OpenCode and OMP.&lt;/li&gt;
&lt;li&gt;It runs on macOS and Linux. Windows is not supported, and WSL is untested.&lt;/li&gt;
&lt;li&gt;The OAuth flow talks to Figma's servers directly. &lt;code&gt;ivar&lt;/code&gt; has no server of its own in the middle.&lt;/li&gt;
&lt;li&gt;The Figma MCP server gives your agent read access to files, frames, comments and component metadata. It does not edit designs, and &lt;code&gt;ivar&lt;/code&gt; does not sync designs into code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/blog/one-mcp-config-claude-code-opencode-omp?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=figma-mcp-opencode" rel="noopener noreferrer"&gt;One MCP config for Claude Code, OpenCode and OMP&lt;/a&gt;: where each harness's MCP auth breaks, and one declaration for all three.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/blog/parallel-features-single-repo?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=figma-mcp-opencode" rel="noopener noreferrer"&gt;One repo, many agents: parallel features from a Figma prototype&lt;/a&gt;: Figma MCP in every parallel session on one repository.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ivar.run/docs/guide/mcp/integrations/figma?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=figma-mcp-opencode" rel="noopener noreferrer"&gt;Figma integration&lt;/a&gt;: the reference page for this setup.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>figma</category>
      <category>opencode</category>
    </item>
    <item>
      <title>The context problem nobody solved: AI agents across multiple repos</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:14:34 +0000</pubDate>
      <link>https://dev.to/mnzs/the-context-problem-nobody-solved-ai-agents-across-multiple-repos-4533</link>
      <guid>https://dev.to/mnzs/the-context-problem-nobody-solved-ai-agents-across-multiple-repos-4533</guid>
      <description>&lt;h2&gt;
  
  
  Why one repo is the unit an agent understands
&lt;/h2&gt;

&lt;p&gt;AI coding agents are fundamentally designed around a single root directory. When you initialize an agentic session—whether using Claude Code, Codex, Aider, or custom CLI execution harnesses—the harness binds directly to the process's current working directory (&lt;code&gt;cwd&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Inside that single repository boundary, the agentic tooling architecture operates cleanly. The harness reads local instruction files such as &lt;code&gt;CLAUDE.md&lt;/code&gt;, &lt;code&gt;.cursorrules&lt;/code&gt;, or &lt;code&gt;AGENTS.md&lt;/code&gt;, indexes the directory tree, connects to local Language Server Protocol (LSP) daemons for symbol resolution and type checking, runs test runners, and inspects git status. The context window is optimized to ingest and edit files relative to that single canonical root.&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%2F89blb7cuiwe56228z6t2.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%2F89blb7cuiwe56228z6t2.png" alt="An agent bound to one repository resolves symbols, tests and git state inside it, and sees nothing of the two repositories the same change touches."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Everything the harness does well stops at the edge of the directory it was pointed at.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, modern software engineering rarely lives within a single repository. Enterprise systems and modern cloud architectures are routinely split across polyrepo boundaries: a Rust core backend, a TypeScript frontend client, an OpenAPI contract repo, an infrastructure-as-code repository, and shared internal utility libraries. &lt;/p&gt;

&lt;p&gt;When a developer asks an agent to perform a feature task that spans multiple repositories—such as updating a database schema, adjusting an API endpoint, and reflecting those contract changes in a web application—the single-repo architecture breaks down across several distinct vectors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LSP and Symbol Resolution Failures&lt;/strong&gt;: Language servers rely on explicit project configuration files (e.g., &lt;code&gt;tsconfig.json&lt;/code&gt;, &lt;code&gt;Cargo.toml&lt;/code&gt;, &lt;code&gt;go.mod&lt;/code&gt;) located at recognized workspace roots. When an agent attempts to inspect code in a sibling directory outside its bound &lt;code&gt;cwd&lt;/code&gt;, the LSP cannot resolve cross-repository types or jump-to-definition targets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Window Noise and Index Pollution&lt;/strong&gt;: Search utilities like &lt;code&gt;grep&lt;/code&gt; or file tree crawlers executed by the harness default to searching relative to the active root. If forced to search higher up the filesystem tree, indexing algorithms ingest unrelated build artifacts, &lt;code&gt;node_modules&lt;/code&gt;, target binaries, and lockfiles, quickly saturating the LLM context window with irrelevancies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git Semantics Breakdown&lt;/strong&gt;: Git operations (&lt;code&gt;git diff&lt;/code&gt;, &lt;code&gt;git status&lt;/code&gt;, &lt;code&gt;git commit&lt;/code&gt;) execute relative to the repository containing &lt;code&gt;cwd&lt;/code&gt;. When an agent edits files in sibling repositories without changing execution directories, git commands fail or apply modifications to the wrong repository context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Session Fragmentation&lt;/strong&gt;: Switching execution directories dynamically within an active agent session resets tool state, loses chain-of-thought context, invalidates cached workspace maps, and frequently leads to agent hallucination regarding file locations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the single repository remains the hard-coded unit of understanding for existing AI harnesses, engineers working across polyrepo architectures are forced to rely on fragile community workarounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five workarounds people actually use
&lt;/h2&gt;

&lt;p&gt;As agentic coding adoption has accelerated across engineering organizations, teams have attempted to bridge the cross-repo context gap. Based on developer surveys, community architecture guides, and technical discussions surrounding multi-repo AI workflows, five primary workarounds have emerged.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workaround&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parent workspace directory&lt;/td&gt;
&lt;td&gt;Opens &lt;code&gt;~/projects/&lt;/code&gt; as the agent root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Meta-repository&lt;/td&gt;
&lt;td&gt;A parent repo with the others as submodules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt and path hacks&lt;/td&gt;
&lt;td&gt;Injects &lt;code&gt;../repo-b&lt;/code&gt; into the instruction file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP context bridge&lt;/td&gt;
&lt;td&gt;Exposes the other repos as read-only search tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-mediated orchestration&lt;/td&gt;
&lt;td&gt;Hands the work to agents behind an API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1. The Parent "Mega" Workspace Directory
&lt;/h3&gt;

&lt;p&gt;The simplest and most common workaround is pointing the AI harness at a top-level parent folder containing all local repositories:&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;cd&lt;/span&gt; ~/projects
claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this layout, &lt;code&gt;~/projects/&lt;/code&gt; acts as the root, placing &lt;code&gt;~/projects/backend-api&lt;/code&gt;, &lt;code&gt;~/projects/web-frontend&lt;/code&gt;, and &lt;code&gt;~/projects/shared-schema&lt;/code&gt; inside the agent's visible directory hierarchy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it breaks:&lt;/strong&gt; Git awareness collapses completely. The parent directory &lt;code&gt;~/projects&lt;/code&gt; is not itself a git repository. Standard harness commands like &lt;code&gt;git status&lt;/code&gt; or &lt;code&gt;git diff&lt;/code&gt; fail immediately with &lt;code&gt;fatal: not a git repository&lt;/code&gt;. Furthermore, file search utilities scan across every cloned repository simultaneously, overloading context limits with irrelevant search hits, while language servers fail to establish root boundaries for auto-completion and type checking.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Meta-Repository with Git Submodules
&lt;/h3&gt;

&lt;p&gt;To restore git tracking at the workspace root, teams construct a meta-repository (often called a "repo-of-repos" or workspace wrapper) that links individual repos as git submodules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/meta-workspace
 ├── .git/
 ├── .gitmodules
 ├── backend-api/     (submodule)
 └── web-frontend/    (submodule)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Where it breaks:&lt;/strong&gt; Git submodules introduce heavy operational overhead and state desynchronization. Modifying code inside a submodule leaves the parent meta-repository in a modified state, requiring a multi-step commit dance (committing inside the submodule, then committing the updated submodule pointer in the meta-repo). Branching becomes particularly error-prone: checking out a feature branch in the meta-repo does not automatically check out matching branches inside submodules, causing submodules to enter a detached HEAD state and confusing the agent's mental model of branch alignment across services.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. System Prompt &amp;amp; Relative Path Guidance
&lt;/h3&gt;

&lt;p&gt;Another prevalent strategy relies on injecting explicit relative path directions into system prompts or repository instruction files (&lt;code&gt;CLAUDE.md&lt;/code&gt;, &lt;code&gt;.cursorrules&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt;):&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;# Multi-Repo Context Rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; The backend API code is located at &lt;span class="sb"&gt;`../backend-api`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; The shared OpenAPI schema is at &lt;span class="sb"&gt;`../shared-schema/openapi.json`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; When updating frontend types, read &lt;span class="sb"&gt;`../shared-schema/openapi.json`&lt;/span&gt; first.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Where it breaks:&lt;/strong&gt; Relying on relative path instructions places the entire burden of path resolution on the LLM's prompt compliance. Under high token loads or multi-step reasoning tasks, models non-deterministically violate relative path boundaries, attempt to write files outside allowed trees, or hallucinate relative directory levels (e.g., &lt;code&gt;../../backend-api&lt;/code&gt;). Additionally, relative paths break bash tool execution: commands run by the agent default to &lt;code&gt;cwd&lt;/code&gt;, producing errors when build scripts or test runners expect to be executed from a sibling repository's root.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. MCP (Model Context Protocol) Context Bridges
&lt;/h3&gt;

&lt;p&gt;With the adoption of MCP, developers construct custom MCP servers that expose search, read, and indexing interfaces to external repositories. An agent operating within &lt;code&gt;web-frontend&lt;/code&gt; calls an MCP tool to fetch function signatures or schema definitions from &lt;code&gt;backend-api&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it breaks:&lt;/strong&gt; MCP bridges provide tool-gated, read-only context retrieval. While an MCP server enables an agent to query code snippets from external repositories, it does not grant the agent the capability to perform native file edits, run local language servers, execute test suites, or manage git commits in the target repository. It solves snippet retrieval but leaves multi-repository execution completely unaddressed.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Server-Mediated Orchestration &amp;amp; Multi-Agent Swarms
&lt;/h3&gt;

&lt;p&gt;For large-scale enterprise environments, organizations construct multi-agent server platforms. A centralized orchestrator agent receives an overall task specification, decomposes it into repository-specific sub-tasks, and dispatches individual agent instances to execute asynchronously against remote repositories via API calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it breaks:&lt;/strong&gt; Server-mediated multi-agent swarms sacrifice the local, interactive developer-in-the-loop workflow. Communication between agents occurs via natural language summaries sent over network APIs, introducing significant latency, high token consumption, and compounding translation errors. When a multi-repo build fails, diagnosing which agent introduced the breaking change across asynchronous API boundaries is difficult and time-consuming.&lt;/p&gt;

&lt;h2&gt;
  
  
  What every workaround has in common
&lt;/h2&gt;

&lt;p&gt;Evaluating these five approaches side-by-side reveals a fundamental structural pattern:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workaround Strategy&lt;/th&gt;
&lt;th&gt;Git Integration&lt;/th&gt;
&lt;th&gt;Local Test Execution&lt;/th&gt;
&lt;th&gt;Write Protection&lt;/th&gt;
&lt;th&gt;Operational Friction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parent Workspace Dir&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Broken (&lt;code&gt;not a git repo&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Unreliable&lt;/td&gt;
&lt;td&gt;Unprotected&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Meta-Repo / Submodules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex (Detached HEAD)&lt;/td&gt;
&lt;td&gt;Local only&lt;/td&gt;
&lt;td&gt;Unprotected&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompt Path Hacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single repo only&lt;/td&gt;
&lt;td&gt;Fails on relative paths&lt;/td&gt;
&lt;td&gt;Soft / Prompt-based&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MCP Context Bridge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (Tool abstraction)&lt;/td&gt;
&lt;td&gt;None (Read-only)&lt;/td&gt;
&lt;td&gt;Read-only&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-Agent Swarms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Isolated per agent&lt;/td&gt;
&lt;td&gt;Asynchronous / Remote&lt;/td&gt;
&lt;td&gt;Isolated per agent&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every community workaround makes a fundamental trade-off between workspace visibility, execution capability, and write protection. &lt;/p&gt;

&lt;p&gt;None of these approaches provides a &lt;strong&gt;real Git worktree on the same feature branch across multiple repositories with write access guarded deterministically at the filesystem layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They inevitably fall into one of three failure modes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They compromise git semantics and language server integration by flattening repositories into plain directories or submodules.&lt;/li&gt;
&lt;li&gt;They rely on soft, non-deterministic prompt rules or software hooks to control file writes, which fail under context pressure.&lt;/li&gt;
&lt;li&gt;They isolate the agent so strictly (via read-only MCP tools or remote swarms) that the agent cannot perform coordinated edits or run cross-repository test suites.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What a view directory is
&lt;/h2&gt;

&lt;p&gt;To overcome the single-repository limitation while preserving native git semantics and execution capabilities, workspace orchestration requires a dedicated abstraction layer: the &lt;strong&gt;View Directory&lt;/strong&gt; (View Dir).&lt;/p&gt;

&lt;p&gt;A View Directory is a materialized, session-specific workspace folder constructed dynamically for an agentic session. Rather than duplicating code or creating nested meta-repositories, a View Directory aggregates registered repositories using native operating system symlinks pointing directly to real Git worktrees.&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%2F3ln4i9vamwci60q6wy35.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%2F3ln4i9vamwci60q6wy35.png" alt="A View Dir holding three symlinks, each pointing at a real git worktree. Two are promoted onto the same feature branch and writable; the third stays on main and read-only."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Each entry is a symlink to a real worktree. Promotion decides which of them the kernel will let the agent write to.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When an agent session initializes within a View Directory:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Promoted Repositories&lt;/strong&gt;: Repositories where active code modifications are planned are mounted as Git worktrees checked out on the exact same feature branch (e.g., &lt;code&gt;feature-x&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpromoted Context Repositories&lt;/strong&gt;: Repositories included solely for reference are mounted as Git worktrees checked out on their default branch (e.g., &lt;code&gt;main&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instruction Resolution&lt;/strong&gt;: Provider-native instruction files (&lt;code&gt;CLAUDE.md&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt;) at the root of the View Dir are dynamically synthesized from a canonical hall configuration (&lt;code&gt;HALL.md&lt;/code&gt;), giving the agent unified multi-repo instructions without dirtying individual repository trees.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because each entry inside a View Directory points to a genuine Git worktree, language servers process cross-repo imports seamlessly through symlinks, build utilities run locally, and git commands maintain total integrity. The &lt;a href="https://ivar.run/docs/what-is-ivar?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ai-coding-agent-multiple-repos" rel="noopener noreferrer"&gt;concepts page&lt;/a&gt; covers the rest of the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read access is not the hard part — write access is
&lt;/h2&gt;

&lt;p&gt;Exposing multiple repositories for reading is trivial; any file crawler or MCP server can ingest text from sibling directories. The true technical challenge in polyrepo agentic development is &lt;strong&gt;enforcing strict write isolation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When an AI agent operates inside a multi-repository workspace, language models frequently attempt unauthorized or out-of-scope file modifications. For example, while updating a frontend component to handle an API change, an agent might attempt to edit a shared library file to fix a lint error, accidentally mutating git state in a shared context repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Prompt-Based and Hook-Based Guards Fail
&lt;/h3&gt;

&lt;p&gt;Traditional agent frameworks attempt to enforce write safety through soft boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System Prompt Instructions&lt;/strong&gt;: Advising the model &lt;code&gt;"Do not modify files inside the /docs or /lib directory"&lt;/code&gt;. As context windows fill and reasoning chains complexify, models non-deterministically ignore prompt constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PreToolUse Hooks&lt;/strong&gt;: Intercepting file-writing tool invocations in software. Hooks add execution latency, are tied to specific harness implementations, and fail to prevent writes executed via raw shell commands (such as &lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, or build script output redirection).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  POSIX Filesystem Guarding (&lt;code&gt;chmod&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;To guarantee absolute safety, write protection must operate below the LLM layer, enforced deterministically by the operating system kernel.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;ivar&lt;/code&gt;, write safety is enforced at the POSIX filesystem level using file permission masks (&lt;code&gt;chmod&lt;/code&gt;). Unpromoted context repositories mounted inside a View Directory are stripped of write bits across their entire worktree tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;0o222&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;chmod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;0o222&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;When an unpromoted repository is mounted:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;clear_write_bits&lt;/code&gt; applies &lt;code&gt;mode &amp;amp; !0o222&lt;/code&gt; recursively to every file and folder in the repository's worktree.&lt;/li&gt;
&lt;li&gt;If an agent attempts to modify a file in an unpromoted repository—whether using a file edit tool, a bash command redirection, or an automated refactoring script—the OS kernel immediately halts the operation with a deterministic &lt;code&gt;EACCES&lt;/code&gt; (Permission Denied) error.&lt;/li&gt;
&lt;li&gt;Neither LLM prompt compliance nor harness hook logic is involved in blocking the write; enforcement occurs directly at the kernel boundary.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When a repository is explicitly promoted to active edit status within the session, &lt;code&gt;restore_write_bits&lt;/code&gt; selectively re-enables write permissions (&lt;code&gt;u+w&lt;/code&gt;), permitting authorized edits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;chmod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0o200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This deterministic mechanism guarantees that read-only context repositories remain strictly immutable throughout the agentic session, regardless of model behavior or shell execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves you
&lt;/h2&gt;

&lt;p&gt;The single-repository constraint has hindered polyrepo agentic development. While community workarounds—from mega-directories to custom MCP servers—have provided temporary stopgaps, none provide a workspace environment that combines native git execution, multi-repo visibility, and deterministic write protection.&lt;/p&gt;

&lt;p&gt;The View Directory pattern replaces soft prompt boundaries and artificial folder structures with a kernel-enforced, worktree-native workspace primitive. OS-enforced permission masks ensure read-only stability across context repositories, while genuine Git worktrees preserve complete compatibility with local development tools and AI harnesses.&lt;/p&gt;

&lt;p&gt;The mechanism behind View Dirs, and the vocabulary it uses, is covered in &lt;a href="https://ivar.run/docs/what-is-ivar?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ai-coding-agent-multiple-repos" rel="noopener noreferrer"&gt;what a View Dir is and why it exists&lt;/a&gt;. To mount your own repositories into one, start with the &lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ai-coding-agent-multiple-repos" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>git</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A code graph for agents that spans repos and parallel features</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:14:30 +0000</pubDate>
      <link>https://dev.to/mnzs/a-code-graph-for-agents-that-spans-repos-and-parallel-features-dme</link>
      <guid>https://dev.to/mnzs/a-code-graph-for-agents-that-spans-repos-and-parallel-features-dme</guid>
      <description>&lt;h2&gt;
  
  
  Where an agent's tokens go
&lt;/h2&gt;

&lt;p&gt;Watch a coding agent start on an unfamiliar change and most of the early turns&lt;br&gt;
look the same. It greps for a name, opens three of the matches, finds an import,&lt;br&gt;
opens that file, greps for the caller, opens two more. Each read puts a whole&lt;br&gt;
file into context, most of which has nothing to do with the question. By the&lt;br&gt;
time it knows where the change goes, it has spent a large share of its budget on&lt;br&gt;
navigation.&lt;/p&gt;

&lt;p&gt;A code graph shortens that loop. If the agent can ask "who calls&lt;br&gt;
&lt;code&gt;renderInvoice&lt;/code&gt;, and what does it touch" and get the answer with the relevant&lt;br&gt;
source attached, it skips the grep-read-grep cycle. That part is not new.&lt;/p&gt;

&lt;p&gt;Two things about how &lt;code&gt;ivar&lt;/code&gt; is used made the usual shape of a code graph a poor&lt;br&gt;
fit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The change spans repositories.&lt;/strong&gt; A hall mounts an API, a web client and a&lt;br&gt;
shared package side by side. The interesting edges are between them: the web&lt;br&gt;
client's HTTP request and the API route that serves it, or a&lt;br&gt;
type exported by the shared package and used in both. An index built per repo&lt;br&gt;
does not have those edges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Several features run at once.&lt;/strong&gt; Each feature is its own branch, checked out as&lt;br&gt;
its own set of worktrees, often with an agent working in each. A graph scoped to&lt;br&gt;
a folder is built for one checkout. Point it at five feature checkouts and you&lt;br&gt;
either index the same repo five times or answer every session from one of them,&lt;br&gt;
which means some agents see code that is not on their branch.&lt;/p&gt;
&lt;h2&gt;
  
  
  The design
&lt;/h2&gt;
&lt;h3&gt;
  
  
  One base, one layer per feature
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ivar graph&lt;/code&gt; keeps a single SQLite database for the hall at &lt;code&gt;.ivar/memory.db&lt;/code&gt;.&lt;br&gt;
It holds a &lt;strong&gt;base index&lt;/strong&gt; of each repo's default branch, shared by every&lt;br&gt;
session. On top of it, each feature gets a &lt;strong&gt;layer&lt;/strong&gt; that holds only the files&lt;br&gt;
the feature changed, committed or not.&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%2Fiz5b2la69tp253w5crfs.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%2Fiz5b2la69tp253w5crfs.png" alt="One base index of every repo's default branch, shared by all sessions, with a small layer per feature holding only the files that feature changed." width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A feature session reads its own layer first and the base for everything else. A discovery session reads the base.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A feature usually changes tens of files, so a layer is small next to the base.&lt;br&gt;
Queries from a feature session resolve symbols against the layer first and fall&lt;br&gt;
back to the base, which is how an agent sees its own edits without the graph&lt;br&gt;
duplicating the rest of the repo.&lt;/p&gt;

&lt;p&gt;Extraction uses tree-sitter and runs in parallel. Base indexing is incremental:&lt;br&gt;
&lt;code&gt;ivar&lt;/code&gt; diffs each repo against the commit it last indexed and checks file size&lt;br&gt;
and modification time, so a rerun parses only what moved.&lt;/p&gt;
&lt;h3&gt;
  
  
  Freshness on every call
&lt;/h3&gt;

&lt;p&gt;A layer goes stale the moment the agent edits a file. Asking the agent to call a&lt;br&gt;
reindex tool after each edit works until it forgets. So before every query the&lt;br&gt;
MCP server compares the layer with the worktree and reindexes the files that&lt;br&gt;
changed.&lt;/p&gt;

&lt;p&gt;That check has to be cheap to run on every call. On a feature with 177 changed&lt;br&gt;
files it took about 18 ms per call, and about 21 ms right after an edit.&lt;/p&gt;

&lt;p&gt;If the layer cannot be refreshed, the call fails with an error. It does not&lt;br&gt;
quietly answer from the base: an answer about code that is no longer on disk is&lt;br&gt;
the kind of wrong an agent acts on with confidence.&lt;/p&gt;
&lt;h3&gt;
  
  
  One query that returns enough to act on
&lt;/h3&gt;

&lt;p&gt;The MCP server advertises one tool by default, &lt;code&gt;graph_explore&lt;/code&gt;. The agent passes&lt;br&gt;
symbol names, paths, or a short intent, several at once. The answer includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the flow between the symbols it named,&lt;/li&gt;
&lt;li&gt;the line-numbered source of the most relevant files, cut to a size budget,&lt;/li&gt;
&lt;li&gt;the blast radius of each definition: its callers and type uses,&lt;/li&gt;
&lt;li&gt;a ready &lt;code&gt;Next:&lt;/code&gt; call with a &lt;code&gt;paths&lt;/code&gt; argument listing the files that did not
fit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The source is the part that removes reads. The &lt;code&gt;Next:&lt;/code&gt; hint is the part that&lt;br&gt;
keeps the agent from falling back to opening files one at a time: a follow-up&lt;br&gt;
with &lt;code&gt;paths&lt;/code&gt; returns up to 12 whole files in one call.&lt;/p&gt;

&lt;p&gt;The other tools (callers, impact, affected tests, paths and more) are available&lt;br&gt;
behind &lt;code&gt;ivar graph mcp --tools all&lt;/code&gt;, and the queries have CLI equivalents, which&lt;br&gt;
matters for providers such as omp that do not pass MCP servers to subagents. A&lt;br&gt;
subagent can run &lt;code&gt;ivar graph explore renderInvoice&lt;/code&gt; in a shell and get the same&lt;br&gt;
answer.&lt;/p&gt;
&lt;h2&gt;
  
  
  What it changed in a benchmark
&lt;/h2&gt;

&lt;p&gt;We ran agents on the same fixture with and without the graph, using the same&lt;br&gt;
model and the same task prompt in both arms. The fixture is two repositories: a Fastify API and a&lt;br&gt;
React web app that calls it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Discovery
&lt;/h3&gt;

&lt;p&gt;The agent explores the fixture to answer a question about how the code works,&lt;br&gt;
and its answer is scored against a hand-built answer key. Three runs per arm.&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;With &lt;code&gt;ivar graph&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Without a graph&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Median tokens&lt;/td&gt;
&lt;td&gt;460k&lt;/td&gt;
&lt;td&gt;738k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File reads&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;12 to 28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answer-key coverage&lt;/td&gt;
&lt;td&gt;93 to 94 %&lt;/td&gt;
&lt;td&gt;91 to 94 %&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The graph arm answered as completely while reading no files; the source it&lt;br&gt;
needed arrived inside the query results. Tokens fell by about 38 %.&lt;/p&gt;
&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;The agent implements a change in the fixture that has to pass an acceptance&lt;br&gt;
suite. Five runs per arm, and every run in both arms passed.&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;With &lt;code&gt;ivar graph&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Without a graph&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Median tokens&lt;/td&gt;
&lt;td&gt;1.53 M&lt;/td&gt;
&lt;td&gt;1.61 M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median file reads&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here the token saving is small, about 5 %. Most of an implementation run is likely&lt;br&gt;
spent editing, running tests and reading their output, and the graph does not&lt;br&gt;
help with that. File reads still fell from 26 to 6, and the reads that remain&lt;br&gt;
are the ones the provider requires before it lets an agent edit a file.&lt;/p&gt;
&lt;h3&gt;
  
  
  On a real hall
&lt;/h3&gt;

&lt;p&gt;The fixture is small, so we also measured the graph on a working hall of about&lt;br&gt;
29,000 files, which indexed to 144,000 symbols and 1.9 million edges.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Index size&lt;/td&gt;
&lt;td&gt;370 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold index&lt;/td&gt;
&lt;td&gt;77 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reindex, no changes&lt;/td&gt;
&lt;td&gt;0.17 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server startup&lt;/td&gt;
&lt;td&gt;about 5 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;graph_explore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;12 to 80 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Callers query&lt;/td&gt;
&lt;td&gt;0.4 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Impact query&lt;/td&gt;
&lt;td&gt;0.2 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Caveats
&lt;/h3&gt;

&lt;p&gt;These are small samples: three and five runs per arm, on one fixture, with one&lt;br&gt;
model. The discovery answer key was built by hand, so coverage is a judgment against&lt;br&gt;
it, not an absolute measure. Token counts vary run to&lt;br&gt;
run, which is why the tables report medians and ranges rather than a single&lt;br&gt;
number. The implementation result in particular should be read as "fewer reads&lt;br&gt;
for about the same cost", not as a large saving.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Build the index from the hall root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ivar graph index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first run also registers the graph MCP server in &lt;code&gt;ivar.json&lt;/code&gt; (pass&lt;br&gt;
&lt;code&gt;--no-mcp&lt;/code&gt; to skip it).&lt;/p&gt;

&lt;p&gt;Then run &lt;code&gt;ivar sync&lt;/code&gt; to write the provider configs, and start a feature session.&lt;br&gt;
&lt;code&gt;ivar sync&lt;/code&gt; also keeps the base index current from then on, and &lt;code&gt;ivar doctor&lt;/code&gt;&lt;br&gt;
reports repos whose index has fallen behind.&lt;/p&gt;

&lt;p&gt;New to ivar? The &lt;a href="https://ivar.run/docs/quickstart?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=code-graph-across-repos-and-features" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; mounts your first hall and opens a&lt;br&gt;
feature in a few minutes; the graph comes with it.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://ivar.run/docs/guide/graph?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=code-graph-across-repos-and-features" rel="noopener noreferrer"&gt;Code graph guide&lt;/a&gt; covers layers and limits, and the&lt;br&gt;
&lt;a href="https://ivar.run/docs/reference/graph?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=code-graph-across-repos-and-features" rel="noopener noreferrer"&gt;reference&lt;/a&gt; lists every subcommand and MCP tool.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>git</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Database with Prisma ORM, Docker and Postgres - NestJs with Passport #02</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Fri, 21 Jan 2022 22:34:06 +0000</pubDate>
      <link>https://dev.to/mnzs/database-with-prisma-orm-docker-and-postgres-nestjs-with-passport-02-180l</link>
      <guid>https://dev.to/mnzs/database-with-prisma-orm-docker-and-postgres-nestjs-with-passport-02-180l</guid>
      <description>&lt;p&gt;In the last post start with a blank configuration, understand how to NestJs works with routes, controllers, and services. Saw how easy is to set up Fastify to optimize our app.&lt;/p&gt;

&lt;p&gt;Now, will set up the database and ORM for interacting and storing our data. We use PostgreSQL for the database using docker to create a default container for the app, will use Prisma for ORM because is the best Orm of the moment for interacting with the database.&lt;/p&gt;




&lt;h2&gt;
  
  
  Docker Container
&lt;/h2&gt;

&lt;p&gt;Now that we have our app up, let's containerize it.&lt;/p&gt;

&lt;p&gt;Start by creating the following files in the project's root directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt; - This file will be responsible for importing the Docker images, dividing them into development and production environments, copying all of our files, and installing dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; - This file will be responsible for defining our containers, required images for the app other services, storage volumes, environment variables, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the &lt;code&gt;Dockerfile&lt;/code&gt; and add&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;# Dockerfile&lt;/span&gt;

&lt;span class="s"&gt;FROM node:alpine As development&lt;/span&gt;

&lt;span class="s"&gt;WORKDIR /usr/src/app&lt;/span&gt;

&lt;span class="s"&gt;COPY package*.json ./&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn add glob rimraf&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn --only=development&lt;/span&gt;

&lt;span class="s"&gt;COPY . .&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn build&lt;/span&gt;

&lt;span class="s"&gt;FROM node:alpine as production&lt;/span&gt;

&lt;span class="s"&gt;ARG NODE_ENV=production&lt;/span&gt;
&lt;span class="s"&gt;ENV NODE_ENV=${NODE_ENV}&lt;/span&gt;

&lt;span class="s"&gt;WORKDIR /usr/src/app&lt;/span&gt;

&lt;span class="s"&gt;COPY package*.json ./&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn add glob rimraf&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn --only=production&lt;/span&gt;

&lt;span class="s"&gt;COPY . .&lt;/span&gt;

&lt;span class="s"&gt;COPY --from=development /usr/src/app/dist ./dist&lt;/span&gt;

&lt;span class="s"&gt;CMD ["node", "dist/main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open the &lt;code&gt;docker-compose.yml&lt;/code&gt; file and add the following code&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;# docker-compose.yml&lt;/span&gt;

&lt;span class="na"&gt;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;3.7"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;:&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;main&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;development&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/usr/src/app&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/usr/src/app/node_modules&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3000:3000&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn start:dev&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&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;postgres:13&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;postgres&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5432:5432&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pgdata:/var/lib/postgresql/data&lt;/span&gt;
&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pgdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file and add the PostgreSQL credentials&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env

# PostgreSQL
POSTGRES_USER=nestAuth
POSTGRES_PASSWORD=nestAuth
POSTGRES_DB=nestAuth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By default, Fastify listens only on the &lt;code&gt;localhost 127.0.0.1&lt;/code&gt; interface. For we access our app from other hosts we need to add &lt;code&gt;0.0.0.0&lt;/code&gt; in the &lt;code&gt;main.ts&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="c1"&gt;// src/main.ts&lt;/span&gt;

&lt;span class="k"&gt;await&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="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0&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;p&gt;Awesome, we have our dockerized, and let's go test then. Run in the terminal for development&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up
&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.amazonaws.com%2Fuploads%2Farticles%2F9bsmxo0gopv85cub02vd.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.amazonaws.com%2Fuploads%2Farticles%2F9bsmxo0gopv85cub02vd.png" alt="Docker running in terminal" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And our app is Running 👏&lt;/p&gt;


&lt;h2&gt;
  
  
  Prisma ORM
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prisma.io" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; is an open-source ORM, it is used as an alternative to writing plain SQL, or using another database access tool such as SQL query builders (like knex.js) or ORMs (like TypeORM and Sequelize).&lt;/p&gt;

&lt;p&gt;Start installing Prisma CLI as a development&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add Prisma -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As a best practice invoke the CLI locally by prefixing it with &lt;code&gt;npx&lt;/code&gt;, to create your initial Prisma setup using the &lt;code&gt;init&lt;/code&gt; command&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx prisma init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command creates a new Prisma directory with the following contents&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;schema.prisma&lt;/code&gt;: Specifies your database connection and contains the database schema&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt;: A dotenv file, typically used to store your database credentials in a group of environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default your database connection it's set to &lt;code&gt;postgresql&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;// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;How our connection type is correct, we will set the &lt;code&gt;DATABASE_URL&lt;/code&gt; in &lt;code&gt;.env&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;DATABASE_URL="postgresql://nestAuth:nestAuth@postgres:5432/nestAuth"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Remember to add in &lt;code&gt;.env&lt;/code&gt; in &lt;code&gt;.gitignore&lt;/code&gt; and create a &lt;code&gt;.env.example&lt;/code&gt; before creating the repository in Github&lt;/p&gt;

&lt;p&gt;Generating the Prisma Client requires the &lt;code&gt;schema.prisma&lt;/code&gt; file. &lt;code&gt;COPY prisma ./prisma/&lt;/code&gt; copies the whole Prisma directory in case you also need the migrations.&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;# Dockerfile&lt;/span&gt;

&lt;span class="s"&gt;FROM node:alpine As development&lt;/span&gt;

&lt;span class="s"&gt;WORKDIR /usr/src/app&lt;/span&gt;

&lt;span class="s"&gt;COPY package*.json ./&lt;/span&gt;

&lt;span class="c1"&gt;# Here Prisma folder to the container&lt;/span&gt;
&lt;span class="s"&gt;COPY prisma ./prisma/&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn add glob rimraf&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn --only=development&lt;/span&gt;

&lt;span class="s"&gt;COPY . .&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn build&lt;/span&gt;

&lt;span class="s"&gt;FROM node:alpine as production&lt;/span&gt;

&lt;span class="s"&gt;ARG NODE_ENV=production&lt;/span&gt;
&lt;span class="s"&gt;ENV NODE_ENV=${NODE_ENV}&lt;/span&gt;

&lt;span class="s"&gt;WORKDIR /usr/src/app&lt;/span&gt;

&lt;span class="s"&gt;COPY package*.json ./&lt;/span&gt;

&lt;span class="c1"&gt;# Here Prisma folder to the container&lt;/span&gt;
&lt;span class="s"&gt;COPY prisma ./prisma/&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn add glob rimraf&lt;/span&gt;

&lt;span class="s"&gt;RUN yarn --only=production&lt;/span&gt;

&lt;span class="s"&gt;COPY . .&lt;/span&gt;

&lt;span class="s"&gt;COPY --from=development /usr/src/app/dist ./dist&lt;/span&gt;

&lt;span class="s"&gt;CMD ["node", "dist/main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  First Model
&lt;/h3&gt;

&lt;p&gt;Now to test the connection we will be creating a &lt;code&gt;User&lt;/code&gt; model, inside &lt;code&gt;schema.prisma&lt;/code&gt; insert&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// prisma/schema.prisma

model User {
  id        Int            @id @default(autoincrement())
  email     String         @unique
  name      String
  password  String
  createdAt DateTime       @default(now())
  updatedAt DateTime       @updatedAt
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With your model in place, you can generate your SQL migration files and run them against the database. Here I use &lt;code&gt;migrate dev&lt;/code&gt; for a run in development mode and set &lt;code&gt;init&lt;/code&gt; name for the migration&lt;/p&gt;

&lt;p&gt;Before this you need up your docker&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and edit your &lt;code&gt;.env&lt;/code&gt; file&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://nestAuth:nestAuth@localhsot:5432/nestAuth"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Always you run &lt;code&gt;prisma migrate&lt;/code&gt; you need change the database host to  &lt;code&gt;localhost&lt;/code&gt; after you rollback to name of your database container.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx prisma migrate dev --name init
&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.amazonaws.com%2Fuploads%2Farticles%2Fp9k2rv1me0rrf4sr0ry7.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.amazonaws.com%2Fuploads%2Farticles%2Fp9k2rv1me0rrf4sr0ry7.png" alt="Run Prisma migration in terminal" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rollback &lt;code&gt;.env&lt;/code&gt; file&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://nestAuth:nestAuth@nestauth:5432/nestAuth"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Good News, is our configuration is working, now our database is in sync with our app 👏&lt;/p&gt;


&lt;h3&gt;
  
  
  Setup Prisma
&lt;/h3&gt;

&lt;p&gt;We will want to abstract away the Prisma Client API for database queries within a service. so let's create a new &lt;code&gt;PrismaService&lt;/code&gt; that takes care of instantiating and&lt;code&gt;PrismaClient&lt;/code&gt; to connecting to your database.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;prisma.service.ts&lt;/code&gt; inside &lt;code&gt;src&lt;/code&gt; folder&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="c1"&gt;// src/prisma.service.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;INestApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnModuleInit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@prisma/client&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="nd"&gt;Injectable&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;class&lt;/span&gt; &lt;span class="nc"&gt;PrismaService&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnModuleInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onModuleInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;enableShutdownHooks&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="nx"&gt;INestApplication&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeExit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="k"&gt;await&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;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&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;h2&gt;
  
  
  First Service
&lt;/h2&gt;

&lt;p&gt;Now we can write a user service to make database calls. So NestJs CLI has a command &lt;code&gt;nest g&lt;/code&gt; to generate services, controllers, strategies, and others structures. For now, we run&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nest g service users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Before start create a service we need to generate types of Prisma Model, we can generate with this&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx prisma generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Inside the &lt;code&gt;src&lt;/code&gt; folder the command creates a &lt;code&gt;users&lt;/code&gt; folder with &lt;code&gt;users.service.ts&lt;/code&gt; and the file test &lt;code&gt;users.service.spec.ts&lt;/code&gt;. To test our database connection let's create a two services&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt;: to get a user using the Prisma interface &lt;code&gt;Prisma.UserWhereUniqueInput&lt;/code&gt; forget user by unique columns&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;createUser&lt;/code&gt;: to create a new user using data from interface &lt;code&gt;Prisma.userCreateInput&lt;/code&gt; that get auto the fields when the model needs to create a new register&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And inside the &lt;code&gt;createUser&lt;/code&gt; we need to encrypt the user password, so let's create a provider for this, in the &lt;code&gt;src&lt;/code&gt; folder create a &lt;code&gt;providers&lt;/code&gt; folder and create a &lt;code&gt;password.ts&lt;/code&gt; file&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="c1"&gt;// src/providers/password.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bcrypt&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;SALT_OR_ROUNDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&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;class&lt;/span&gt; &lt;span class="nc"&gt;PasswordProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SALT_OR_ROUNDS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;comparePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compareSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&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;The class has two methods, &lt;code&gt;hashPassword&lt;/code&gt; and &lt;code&gt;comparePassword&lt;/code&gt; to encrypt and compare the password using brcypt. Inside the &lt;code&gt;UsersService&lt;/code&gt; class we need to add in the constructor the provider &lt;code&gt;PasswordProvider&lt;/code&gt; for use in the methods.&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="c1"&gt;// src/users/users.service.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../prisma.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Prisma&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PasswordProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/providers/password&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="nd"&gt;Injectable&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;class&lt;/span&gt; &lt;span class="nc"&gt;UsersService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;passwordProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PasswordProvider&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;userWhereUniqueInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserWhereUniqueInput&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&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;&amp;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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userWhereUniqueInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&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;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserCreateInput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;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;userExists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;},&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;userExists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User already exists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CONFLICT&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;passwordHashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passwordProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&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="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;passwordHashed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&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;user&lt;/span&gt;&lt;span class="p"&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;With service created let's create a controller for route use that&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nest g controller users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So this command create &lt;code&gt;users.controller.ts&lt;/code&gt; and our test file inside &lt;code&gt;src/users&lt;/code&gt;, so let's create two functions in the controller&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;signUpUser&lt;/code&gt;: For run &lt;code&gt;createUser&lt;/code&gt; service and return a data from them&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getUserProfile&lt;/code&gt;: Get an id of the user sent by the route and run the &lt;code&gt;user&lt;/code&gt; service to find them
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/users/users.controller.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./users.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Set prefix route for this group. Ex.: for get profile /users/8126321&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&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;class&lt;/span&gt; &lt;span class="nc"&gt;UsersController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="c1"&gt;// Create user -&amp;gt; POST /users&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;signupUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get user Profile -&amp;gt; GET /users/:id&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&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;/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&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="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;Inside the &lt;code&gt;users.module.ts&lt;/code&gt; file we need to add the providers, exports, and controllers array.&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="c1"&gt;// src/users/users.module.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/prisma.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PasswordProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/providers/password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UsersController&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./users.controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./users.service&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="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PasswordProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UsersController&lt;/span&gt;&lt;span class="p"&gt;],&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;class&lt;/span&gt; &lt;span class="nc"&gt;UsersModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And pass the &lt;code&gt;UsersModule&lt;/code&gt; to the &lt;code&gt;AppModule&lt;/code&gt; for use.&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="c1"&gt;//src/app.module.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppController&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./prisma.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UsersModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./users/users.module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./users/users.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PasswordProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./providers/password&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="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UsersModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppController&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PrismaService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PasswordProvider&lt;/span&gt;&lt;span class="p"&gt;],&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;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's Test
&lt;/h2&gt;

&lt;p&gt;Now lets up our docker container&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up
&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.amazonaws.com%2Fuploads%2Farticles%2Fb6qanohdrojk3rwwr2mb.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.amazonaws.com%2Fuploads%2Farticles%2Fb6qanohdrojk3rwwr2mb.png" alt="Docker running" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it! The app is running 👏&lt;/p&gt;

&lt;p&gt;So in Postman let's try using the &lt;code&gt;createUser&lt;/code&gt; and &lt;code&gt;getProfile&lt;/code&gt; routes&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request POST 'http://0.0.0.0:3000/users' \
--header 'Content-Type: application/json' \
--data-raw '{
    "email": "test@e3x.com",
    "name": "Gabriel Menezes",
    "password": "123123"
}'
&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.amazonaws.com%2Fuploads%2Farticles%2Fl1egknq2su4kua7n7tjs.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.amazonaws.com%2Fuploads%2Farticles%2Fl1egknq2su4kua7n7tjs.png" alt="Create user route" width="800" height="395"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request GET 'http://0.0.0.0:3000/users/37'
&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.amazonaws.com%2Fuploads%2Farticles%2Fr2vcxvswlk9m2kckkpvq.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.amazonaws.com%2Fuploads%2Farticles%2Fr2vcxvswlk9m2kckkpvq.png" alt="Get user route" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Until Next Time
&lt;/h2&gt;

&lt;p&gt;That is all we are going to cover in this article, we dockerize the app, set up Prisma, and create two routes. In the next piece in the series, we'll create and define our Auth providers for authenticating in our app.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;



&lt;p&gt;Follow repository to consulting code&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mnzsss" rel="noopener noreferrer"&gt;
        mnzsss
      &lt;/a&gt; / &lt;a href="https://github.com/mnzsss/nest-auth-explained" rel="noopener noreferrer"&gt;
        nest-auth-explained
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🔒 Authentication using JWT and Google with Nest.js Explained
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;






&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/erezhod/setting-up-a-nestjs-project-with-docker-for-back-end-development-30lg"&gt;Setting up a NestJS project with Docker for Back-End development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://notiz.dev/blog/dockerizing-nestjs-with-prisma-and-postgresql" rel="noopener noreferrer"&gt;Dockerizing a NestJS app with Prisma and PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>nestjs</category>
      <category>tutorial</category>
      <category>prisma</category>
    </item>
    <item>
      <title>Setup Project and Fastify Platform - NestJs with Passport #01</title>
      <dc:creator>Gabriel Menezes</dc:creator>
      <pubDate>Thu, 06 Jan 2022 21:49:49 +0000</pubDate>
      <link>https://dev.to/mnzs/setup-project-and-fastify-platform-nestjs-with-passport-01-27jl</link>
      <guid>https://dev.to/mnzs/setup-project-and-fastify-platform-nestjs-with-passport-01-27jl</guid>
      <description>&lt;p&gt;In this series of posts I will create an Authentication system with Passport using social auth and JWT. Let's use the combination of NestJs + Passport + Fastify to create a complete authentication system.&lt;/p&gt;

&lt;p&gt;So in this first part, we start with a blank project and will use the Fastify Platform and understand how NestJs works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is NestJs?
&lt;/h2&gt;

&lt;p&gt;NestJs is a framework for building efficient and scalable Node.js server-side applications. It uses robust HTTP Server frameworks like Express or Fastify. NestJs provides a level of abstraction above the common Node.js frameworks and exposes their APIs to the developer. This gives a great amount of freedom to use third-party modules.&lt;/p&gt;

&lt;p&gt;Used for writing scalable, testable, and loosely coupled applications. It supports databases like PostgreSQL, MongoDB, MySQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start Project
&lt;/h2&gt;

&lt;p&gt;We will use the &lt;code&gt;@nestjs/cli&lt;/code&gt; to create a starter project and clear the files when we don't use them in our project. If you want to see the details, check the official documentation.&lt;/p&gt;

&lt;p&gt;First, we install &lt;code&gt;@nestjs/cli&lt;/code&gt; globally in your computer and initialize a blank project. I recommend using yarn for installing packages, but you can choose a package manager your preference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn global add @nestjs/cli
nest new nest-auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And you access the folder and run in VSCode (or in another editor if you prefer).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd nest-auth
code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the image below, you see the file structure, when we have an app module, controller, and service.&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.amazonaws.com%2Fuploads%2Farticles%2Fc68uviuxhqgivxo6o1zk.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.amazonaws.com%2Fuploads%2Farticles%2Fc68uviuxhqgivxo6o1zk.png" alt="Folder Structure for Nest-Auth" width="320" height="467"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Type of blocks in NestJs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Modules:&lt;/strong&gt; used to organize the code and split features into logical reusable units. Grouped TypeScript files are decorated with “@Module” decorator which provides metadata that NestJs makes use of to organize the application structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Providers:&lt;/strong&gt; also called services, which are designed to abstract any form of complexity and logic. Providers can be created and injected into controllers or other providers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controllers:&lt;/strong&gt; responsible for handling incoming requests and returning appropriate responses to the client-side of the application (for example call to the API).&lt;/p&gt;
&lt;h2&gt;
  
  
  Configure Fastify Platform
&lt;/h2&gt;

&lt;p&gt;In this project, I choose to use Fastify because it has a much better performance and functionalities than Express.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fastify provides a good alternative framework for Nest because it solves design issues in a similar manner to Express. However, fastify is much faster than Express, achieving almost two times better benchmarks results. A fair question is why does Nest use Express as the default HTTP provider? The reason is that Express is widely-used, well-known, and has an enormous set of compatible middleware, which is available to Nest users out-of-the-box.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let's configure that, in &lt;code&gt;main.ts&lt;/code&gt; we configure the platform if we use Fastify.&lt;/p&gt;

&lt;p&gt;First, we need to install the required package:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @nestjs/platform-fastify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And in &lt;code&gt;src/main.ts&lt;/code&gt; you import &lt;code&gt;FastifyAdapter&lt;/code&gt; and &lt;code&gt;NestFastifyApplication&lt;/code&gt; for initialize that in &lt;code&gt;NestFactory.create&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="c1"&gt;// src/main.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;FastifyAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;NestFastifyApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/platform-fastify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrap&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;app&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;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NestFastifyApplication&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;AppModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FastifyAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&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="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We don't need any more settings, now Fastify is configured and ready to use 👏&lt;/p&gt;
&lt;h2&gt;
  
  
  Run First Route
&lt;/h2&gt;

&lt;p&gt;When making a project using &lt;code&gt;@nestjs/cli&lt;/code&gt; it creates an example route, so will use that route to test our configuration. In the next tutorials, I explain how routes work in NestJs. Now we want to know if Fastify is working.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;app.controller&lt;/code&gt; file, our see a default route using GET method in &lt;code&gt;/&lt;/code&gt; path when using the &lt;code&gt;http://localhost:3000/&lt;/code&gt; the server run &lt;code&gt;getHello&lt;/code&gt; function and return a response from &lt;code&gt;AppService&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="c1"&gt;// src/app.controller.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.service&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="nd"&gt;Controller&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;class&lt;/span&gt; &lt;span class="nc"&gt;AppController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;appService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;getHello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHello&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;The &lt;code&gt;AppService&lt;/code&gt; has a method called &lt;code&gt;getHello&lt;/code&gt; that returns a string &lt;code&gt;Hello World&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="c1"&gt;// src/app.service.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&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="nd"&gt;Injectable&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;class&lt;/span&gt; &lt;span class="nc"&gt;AppService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getHello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World!&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So let's send a request using Postman for this route and see what returns&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.amazonaws.com%2Fuploads%2Farticles%2Faif66l6oxo7u3xkgraoi.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.amazonaws.com%2Fuploads%2Farticles%2Faif66l6oxo7u3xkgraoi.png" alt="Postman Route Return" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good news its working 👏&lt;/p&gt;
&lt;h3&gt;
  
  
  Logger
&lt;/h3&gt;

&lt;p&gt;If you want to get a log always that you send one request you can set this option inside &lt;code&gt;Fastify Adapter&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="c1"&gt;// src/main.ts&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrap&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;app&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;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NestFastifyApplication&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;AppModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FastifyAdapter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;logger&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="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&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="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here is an example if you use this option&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.amazonaws.com%2Fuploads%2Farticles%2Fav8msrre4a3b3ndv98s8.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.amazonaws.com%2Fuploads%2Farticles%2Fav8msrre4a3b3ndv98s8.png" alt="Terminal logger" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Until Next Time
&lt;/h2&gt;

&lt;p&gt;That is all we are going to cover in this article, we understood about NestJs and made an initial setup for our project to grow. In the next piece in the series, we'll configure the Database using Prisma, Docker, and Postgresql.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;



&lt;p&gt;Follow repository to consulting code&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mnzsss" rel="noopener noreferrer"&gt;
        mnzsss
      &lt;/a&gt; / &lt;a href="https://github.com/mnzsss/nest-auth-explained" rel="noopener noreferrer"&gt;
        nest-auth-explained
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🔒 Authentication using JWT and Google with Nest.js Explained
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;






&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.nestjs.com/" rel="noopener noreferrer"&gt;NestJs Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://selleo.com/blog/why-choose-nest-js-as-your-backend-framework" rel="noopener noreferrer"&gt;Why Choose NestJS As Your Backend Framework?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nestjs</category>
      <category>tutorial</category>
      <category>backend</category>
      <category>fastify</category>
    </item>
  </channel>
</rss>
