<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>nextjs-nestapi Blog</title>
        <link>https://nextjsnestapi.github.io/blog</link>
        <description>nextjs-nestapi Blog</description>
        <lastBuildDate>Wed, 26 Aug 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Plain route handlers vs. nextjs-nestapi: a side-by-side comparison]]></title>
            <link>https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi</link>
            <guid>https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi</guid>
            <pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The same small CRUD API, written as plain Next.js App Router route handlers and again with nextjs-nestapi — file count, validation, and error handling compared directly.]]></description>
            <content:encoded><![CDATA[<p>Next.js App Router route handlers are just functions — <code>GET</code>, <code>POST</code>, whatever you
export. That's the whole appeal: no framework, no ceremony, straight to the Web
<code>Request</code>/<code>Response</code> APIs. It's also exactly where the pain starts once an API grows past
two or three endpoints. This post builds the same small <code>Post</code> resource twice — once with
plain route handlers, once with <code>nextjs-nestapi</code> — and compares what actually changed.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-api-list-get-one-create">The API: list, get one, create<a href="https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi#the-api-list-get-one-create" class="hash-link" aria-label="Direct link to The API: list, get one, create" title="Direct link to The API: list, get one, create" translate="no">​</a></h2>
<p>Both versions expose:</p>
<ul>
<li class=""><code>GET /api/posts</code> — list posts</li>
<li class=""><code>GET /api/posts/:id</code> — get one post</li>
<li class=""><code>POST /api/posts</code> — create a post, with <code>title</code>/<code>content</code> validation</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="plain-route-handlers">Plain route handlers<a href="https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi#plain-route-handlers" class="hash-link" aria-label="Direct link to Plain route handlers" title="Direct link to Plain route handlers" translate="no">​</a></h2>
<p>Two files, one per route segment, because that's how App Router file-based routing works:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">app/api/posts/route.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">NextRequest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"next/server"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">db</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@/lib/db"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">GET</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> posts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findMany</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">posts</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">POST</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> NextRequest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> body </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">message</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"title is required"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">400</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">typeof</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">content </span><span class="token operator" style="color:#393A34">!==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">message</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"content is required"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">400</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> post </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">data</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">title</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> content</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">201</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">app/api/posts/[id]/route.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">NextRequest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"next/server"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">db</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@/lib/db"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">GET</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  _request</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> NextRequest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">params</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">params</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> params</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> post </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findUnique</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">where</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">message</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Not Found"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">404</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Nothing here is wrong, exactly — but look at what's already crept in with just three
routes:</p>
<ul>
<li class="">Validation is hand-rolled, inline, and ad hoc. <code>title</code> gets a length check;
<code>content</code> doesn't. Nobody decided that on purpose — it's just what got typed.</li>
<li class="">The "not found" response shape (<code>{message: "Not Found"}</code>) has to be remembered and
retyped in every route that needs it. A fourth route will either copy-paste it or
quietly return something slightly different.</li>
<li class="">There is no single place that lists "every route this API has." You reconstruct it by
browsing the <code>app/api</code> folder tree.</li>
</ul>
<p>None of that is a problem at three routes. It's the shape of the problem at thirty.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-same-api-with-nextjs-nestapi">The same API with nextjs-nestapi<a href="https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi#the-same-api-with-nextjs-nestapi" class="hash-link" aria-label="Direct link to The same API with nextjs-nestapi" title="Direct link to The same API with nextjs-nestapi" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">src/features/post/dto.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">IsString</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> MinLength</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"class-validator"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CreatePostDto</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">IsString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">MinLength</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  title</span><span class="token operator" style="color:#393A34">!</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">IsString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  content</span><span class="token operator" style="color:#393A34">!</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">src/features/post/controller.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Controller</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Get</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Post</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Body</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">RouteContext</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"nextjs-nestapi"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">CreatePostDto</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dto"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">db</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@/lib/db"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Controller</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/posts"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">PostController</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">list</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findMany</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/:id"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> RouteContext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> post </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findUnique</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">where</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">params</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">message</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Not Found"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">404</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> post</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Body</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">CreatePostDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> dto</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CreatePostDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">post</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">data</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> dto</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Registered once in <code>app.ts</code>, dispatched through the one catch-all route every controller
shares — see the <a class="" href="https://nextjsnestapi.github.io/quick-start">Quick start</a> if you haven't wired that up yet.</p>
<p>The <code>POST</code> handler here has no validation code in it at all. <code>@Body(CreatePostDto)</code>
parses the request body, runs it against the DTO's <code>class-validator</code> decorators, and
either injects a validated <code>CreatePostDto</code> instance or short-circuits with a structured
<code>422</code>-shaped error — before <code>create()</code> ever runs:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"success"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"message"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Validation failed"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"errors"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token property" style="color:#36acaa">"field"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"title"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"message"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"title should not be empty"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p><code>content</code> is validated too, because leaving a field unvalidated now takes a deliberate
choice — deleting a decorator — rather than just not getting around to writing a check.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="side-by-side">Side by side<a href="https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi#side-by-side" class="hash-link" aria-label="Direct link to Side by side" title="Direct link to Side by side" translate="no">​</a></h2>
<table><thead><tr><th></th><th>Plain route handlers</th><th>nextjs-nestapi</th></tr></thead><tbody><tr><td>Files for 3 routes</td><td>2 (<code>route.ts</code>, <code>[id]/route.ts</code>)</td><td>2 (<code>controller.ts</code>, <code>dto.ts</code>) — stays 2 as you add more methods to the same resource</td></tr><tr><td>Validation</td><td>Hand-written <code>if</code> checks, easy to skip a field</td><td>Declarative, on the DTO, enforced before the handler runs</td></tr><tr><td>Error response shape</td><td>Whatever you typed this time</td><td>Consistent, generated by <code>@Body()</code></td></tr><tr><td>"What routes exist?"</td><td>Reconstruct from the <code>app/api</code> folder tree</td><td>Read the <code>@Controller</code>/<code>@Get</code>/<code>@Post</code> decorators on one class</td></tr><tr><td>API docs</td><td>Write and maintain separately, or skip them</td><td><code>generateOpenApiDocument()</code> reads the same decorators — see <a class="" href="https://nextjsnestapi.github.io/openapi-swagger">OpenAPI / Swagger docs</a></td></tr><tr><td>New project boilerplate</td><td>You write it</td><td><code>npx nextjs-nestapi new my-app</code></td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-plain-route-handlers-are-still-the-right-call">When plain route handlers are still the right call<a href="https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi#when-plain-route-handlers-are-still-the-right-call" class="hash-link" aria-label="Direct link to When plain route handlers are still the right call" title="Direct link to When plain route handlers are still the right call" translate="no">​</a></h2>
<p>This isn't a "always use a framework" post. Reach for plain route handlers when:</p>
<ul>
<li class=""><strong>It's one or two endpoints.</strong> A webhook receiver or a health check doesn't need a
controller class for one function.</li>
<li class=""><strong>You want the file tree to <em>be</em> the route map.</strong> Some teams specifically like that
<code>app/api/posts/[id]/route.ts</code> tells you the URL just by existing. <code>nextjs-nestapi</code>
trades that for decorator-based organization behind a single catch-all route.</li>
<li class=""><strong>You're validating nothing, or almost nothing.</strong> If a route has no request body worth
validating, <code>@Body()</code> isn't buying you anything.</li>
</ul>
<p>And the reverse: reach for <code>nextjs-nestapi</code> once you notice the same validation
boilerplate, the same error shape, and the same "which file was that route in again?"
friction showing up more than once. That's the point where a few decorators pay for
themselves.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it">Try it<a href="https://nextjsnestapi.github.io/blog/plain-route-handlers-vs-nextjs-nestapi#try-it" class="hash-link" aria-label="Direct link to Try it" title="Direct link to Try it" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npx nextjs-nestapi new my-app</span><br></div></code></pre></div></div>
<p>Then walk through the <a class="" href="https://nextjsnestapi.github.io/quick-start">Quick start</a>, or read how
<a class="" href="https://nextjsnestapi.github.io/core-concepts/dto-validation">DTO validation</a> actually works under the hood.</p>]]></content:encoded>
            <category>Guide</category>
        </item>
        <item>
            <title><![CDATA[Scaffold a new project in seconds with the CLI]]></title>
            <link>https://nextjsnestapi.github.io/blog/cli-scaffolding</link>
            <guid>https://nextjsnestapi.github.io/blog/cli-scaffolding</guid>
            <pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[nextjs-nestapi new, init, and generate controller — bootstrap a project or add a feature without hand-writing boilerplate.]]></description>
            <content:encoded><![CDATA[<p>Wiring up <code>app.ts</code>, the catch-all route, and <code>tsconfig.json</code>'s decorator flags by hand is
only a few minutes of work — but it's a few minutes you'll repeat on every new project or
feature. The <code>nextjs-nestapi</code> CLI does it for you.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="starting-a-brand-new-project">Starting a brand new project<a href="https://nextjsnestapi.github.io/blog/cli-scaffolding#starting-a-brand-new-project" class="hash-link" aria-label="Direct link to Starting a brand new project" title="Direct link to Starting a brand new project" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npx nextjs-nestapi new my-app</span><br></div></code></pre></div></div>
<p>This runs <code>create-next-app</code> under the hood, then:</p>
<ul>
<li class="">writes <code>src/app.ts</code> with an empty <code>createApplication({ controllers: [] })</code></li>
<li class="">writes <code>src/app/api/[[...route]]/route.ts</code>, the catch-all dispatcher</li>
<li class="">patches <code>tsconfig.json</code> with <code>experimentalDecorators</code>/<code>emitDecoratorMetadata</code></li>
<li class="">installs <code>nextjs-nestapi</code>, <code>class-validator</code>, and <code>class-transformer</code></li>
</ul>
<p>Add <code>--swagger</code> to also scaffold <code>/api/openapi.json</code> and <code>/api-docs</code> (see the
<a class="" href="https://nextjsnestapi.github.io/openapi-swagger">OpenAPI / Swagger docs</a> post).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wiring-an-existing-project">Wiring an existing project<a href="https://nextjsnestapi.github.io/blog/cli-scaffolding#wiring-an-existing-project" class="hash-link" aria-label="Direct link to Wiring an existing project" title="Direct link to Wiring an existing project" translate="no">​</a></h2>
<p>Already have a Next.js App Router project? <code>init</code> does the same wiring without the
<code>create-next-app</code> step:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npx nextjs-nestapi init </span><span class="token parameter variable" style="color:#36acaa">--swagger</span><br></div></code></pre></div></div>
<p>It never overwrites a file that already exists unless you pass <code>--force</code>, and if it can't
patch <code>tsconfig.json</code> automatically (say, because <code>compilerOptions</code> isn't where it
expects), it tells you exactly what to add by hand instead of guessing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="adding-a-feature">Adding a feature<a href="https://nextjsnestapi.github.io/blog/cli-scaffolding#adding-a-feature" class="hash-link" aria-label="Direct link to Adding a feature" title="Direct link to Adding a feature" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npx nextjs-nestapi generate controller student</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># or the short alias:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">npx nextjs-nestapi g controller student</span><br></div></code></pre></div></div>
<p>This scaffolds:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">src/features/student/controller.ts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">src/features/student/dto.ts</span><br></div></code></pre></div></div>
<p>and, if <code>src/app.ts</code> has a recognizable <code>controllers: [...]</code> array, registers
<code>StudentController</code> there automatically — import added, array updated. If the shape of
<code>app.ts</code> isn't recognized, the command leaves it untouched and prints what to add
yourself, rather than risk corrupting a file it can't parse confidently.</p>
<p>Full reference: <a class="" href="https://nextjsnestapi.github.io/cli">CLI</a>.</p>]]></content:encoded>
            <category>Guide</category>
            <category>CLI</category>
        </item>
        <item>
            <title><![CDATA[Auto-generate OpenAPI docs from your decorators]]></title>
            <link>https://nextjsnestapi.github.io/blog/openapi-swagger-docs</link>
            <guid>https://nextjsnestapi.github.io/blog/openapi-swagger-docs</guid>
            <pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Turn your existing @Controller/@Body decorators into a live OpenAPI document and a self-hosted Swagger UI — no separate doc-writing step.]]></description>
            <content:encoded><![CDATA[<p>If you're already annotating controllers with <code>@Controller</code>, <code>@Get</code>/<code>@Post</code>, and
<code>@Body(DtoClass)</code>, you've already written most of what an OpenAPI document needs. This
post shows how <code>nextjs-nestapi</code> turns that into a live spec and a Swagger UI, with no
separate documentation step to keep in sync.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-the-two-extra-pieces">Install the two extra pieces<a href="https://nextjsnestapi.github.io/blog/openapi-swagger-docs#install-the-two-extra-pieces" class="hash-link" aria-label="Direct link to Install the two extra pieces" title="Direct link to Install the two extra pieces" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> class-validator-jsonschema swagger-ui-dist</span><br></div></code></pre></div></div>
<ul>
<li class=""><code>class-validator-jsonschema</code> turns your <code>class-validator</code> DTOs into JSON Schema.</li>
<li class=""><code>swagger-ui-dist</code> ships the actual Swagger UI assets — served straight from your own
<code>node_modules</code>, not vendored in the library and not pulled from a CDN.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="optional-annotate-for-nicer-docs">Optional: annotate for nicer docs<a href="https://nextjsnestapi.github.io/blog/openapi-swagger-docs#optional-annotate-for-nicer-docs" class="hash-link" aria-label="Direct link to Optional: annotate for nicer docs" title="Direct link to Optional: annotate for nicer docs" translate="no">​</a></h2>
<p>Routes are documented either way; <code>@ApiTags</code>/<code>@ApiOperation</code>/<code>@ApiResponse</code> just add
human-readable metadata:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Controller</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Post</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Body</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ApiTags</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ApiOperation</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ApiResponse</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"nextjs-nestapi"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">ApiTags</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Hello"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Controller</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/hello"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">HelloController</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">ApiOperation</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">summary</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Create a hello"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">ApiResponse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> description</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Created"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Body</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">CreateHelloDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> dto</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CreateHelloDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">created</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> dto</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="expose-the-document-and-the-ui">Expose the document and the UI<a href="https://nextjsnestapi.github.io/blog/openapi-swagger-docs#expose-the-document-and-the-ui" class="hash-link" aria-label="Direct link to Expose the document and the UI" title="Direct link to Expose the document and the UI" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">app/api/openapi.json/route.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">NextResponse</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"next/server"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">generateOpenApiDocument</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"nextjs-nestapi"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@/app"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// populates the decorator registries</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">GET</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">generateOpenApiDocument</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">title</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"My API"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">app/api-docs/[[...file]]/route.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">createSwaggerUiHandler</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"nextjs-nestapi"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">GET</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createSwaggerUiHandler</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">openApiUrl</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/api/openapi.json"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-one-config-flag-you-need">The one config flag you need<a href="https://nextjsnestapi.github.io/blog/openapi-swagger-docs#the-one-config-flag-you-need" class="hash-link" aria-label="Direct link to The one config flag you need" title="Direct link to The one config flag you need" translate="no">​</a></h2>
<p><code>createSwaggerUiHandler</code> resolves <code>swagger-ui-dist</code> with a dynamic <code>import()</code> at request
time. Turbopack and webpack both try to bundle that call by default and fail — mark the
package external and it resolves correctly:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">next.config.ts</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> nextConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> NextConfig </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  serverExternalPackages</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"swagger-ui-dist"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>Skip this and the Swagger UI's static assets (<code>swagger-ui-bundle.js</code>, <code>swagger-ui.css</code>)
will 404.</p>
<p>That's it — visit <code>/api-docs</code> for the UI, <code>/api/openapi.json</code> for the raw spec. Full
reference: <a class="" href="https://nextjsnestapi.github.io/openapi-swagger">OpenAPI / Swagger docs</a>.</p>]]></content:encoded>
            <category>Guide</category>
            <category>OpenAPI</category>
        </item>
        <item>
            <title><![CDATA[Introducing nextjs-nestapi]]></title>
            <link>https://nextjsnestapi.github.io/blog/introducing-nextjs-nestapi</link>
            <guid>https://nextjsnestapi.github.io/blog/introducing-nextjs-nestapi</guid>
            <pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[NestJS-style controllers, DTO validation, and middleware for the Next.js App Router — no DI container, no second framework.]]></description>
            <content:encoded><![CDATA[<p>Next.js App Router route handlers are fast and simple — and that simplicity starts to
hurt once an API grows past a handful of endpoints. Every route is its own file, request
parsing is manual, and there's no shared structure for organizing controllers, validating
input, or documenting what you've built.</p>
<p>NestJS solves exactly this with controllers, decorators, and DTOs — but pulling in a full
Nest runtime (modules, a DI container, its own HTTP adapter) inside a Next.js app is a lot
of machinery for what is usually just "organize my API routes."</p>
<p><strong><code>nextjs-nestapi</code> is the middle ground.</strong></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-it-looks-like">What it looks like<a href="https://nextjsnestapi.github.io/blog/introducing-nextjs-nestapi#what-it-looks-like" class="hash-link" aria-label="Direct link to What it looks like" title="Direct link to What it looks like" translate="no">​</a></h2>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Controller</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Get</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Post</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Body</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">RouteContext</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"nextjs-nestapi"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">CreateHelloDto</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dto"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Controller</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/hello"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">HelloController</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/:id"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">getOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> RouteContext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">params</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token decorator at operator" style="color:#393A34">@</span><span class="token decorator function" style="color:#d73a49">Body</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">CreateHelloDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> dto</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> CreateHelloDto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">created</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> dto</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>One catch-all <code>app/api/[[...route]]/route.ts</code> dispatches every request to your registered
controllers. <code>@Body(DtoClass)</code> validates the request against a <code>class-validator</code> DTO and
returns a structured error response automatically when it fails. No DI container, no
modules — just plain classes wired together with <code>createApplication()</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-not-just-use-nestjss-own-nextjs-adapter-or-plain-route-handlers">Why not just use NestJS's own Next.js adapter, or plain route handlers?<a href="https://nextjsnestapi.github.io/blog/introducing-nextjs-nestapi#why-not-just-use-nestjss-own-nextjs-adapter-or-plain-route-handlers" class="hash-link" aria-label="Direct link to Why not just use NestJS's own Next.js adapter, or plain route handlers?" title="Direct link to Why not just use NestJS's own Next.js adapter, or plain route handlers?" translate="no">​</a></h2>
<ul>
<li class=""><strong>Plain route handlers</strong> work fine for a few endpoints, but you end up hand-rolling the
same body-parsing, validation, and error-shaping logic in every file.</li>
<li class=""><strong>A full NestJS app running inside Next.js</strong> gives you all of that back, plus a DI
container, modules, guards, pipes, and interceptors you may not need — and a second
framework's request lifecycle running alongside Next.js's own.</li>
</ul>
<p><code>nextjs-nestapi</code> picks a narrower scope on purpose: routing, DTO validation, and
middleware, implemented directly on top of <code>NextRequest</code>/<code>NextResponse</code>. See
<a class="" href="https://nextjsnestapi.github.io/limitations">Limitations</a> for the full list of what's deliberately left out.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="get-started">Get started<a href="https://nextjsnestapi.github.io/blog/introducing-nextjs-nestapi#get-started" class="hash-link" aria-label="Direct link to Get started" title="Direct link to Get started" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npx nextjs-nestapi new my-app</span><br></div></code></pre></div></div>
<p>or wire it into an existing project:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> nextjs-nestapi class-validator class-transformer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">npx nextjs-nestapi init</span><br></div></code></pre></div></div>
<p>Head to the <a class="" href="https://nextjsnestapi.github.io/quick-start">Quick start</a> to build your first controller.</p>]]></content:encoded>
            <category>Release</category>
        </item>
    </channel>
</rss>