<?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: Jack Hsu</title>
    <description>The latest articles on DEV Community by Jack Hsu (@jaysoo).</description>
    <link>https://dev.to/jaysoo</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1031211%2F9435a037-2ed3-4275-ba34-e04c20706f4d.jpeg</url>
      <title>DEV Community: Jack Hsu</title>
      <link>https://dev.to/jaysoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jaysoo"/>
    <language>en</language>
    <item>
      <title>Building a Node API with Fastify, esbuild, and Nx</title>
      <dc:creator>Jack Hsu</dc:creator>
      <pubDate>Tue, 28 Feb 2023 15:18:30 +0000</pubDate>
      <link>https://dev.to/nx/building-a-node-api-with-fastify-esbuild-and-nx-1g7g</link>
      <guid>https://dev.to/nx/building-a-node-api-with-fastify-esbuild-and-nx-1g7g</guid>
      <description>&lt;p&gt;There are many decisions to make when it comes to building a Node API. There are a variety of frameworks to choose from (Express, Fastify, Koa, etc.), and a million different ways to build and deploy the application.&lt;/p&gt;

&lt;p&gt;In this article, I’ll show you the easiest way to go from zero to production by using Nx to create a Node API project.&lt;/p&gt;

&lt;p&gt;We’ll be using &lt;a href="https://www.fastify.io/" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt; as the framework of choice. Fastify is a fast (as the name implies) and low-overhead server in Node. It has grown in popularity, recently crossing the 1 million weekly download mark on npm. I’m a fan of Fastify’s plugin architecture, and the ecosystem is quite impressive, boasting over &lt;a href="https://www.fastify.io/ecosystem/" rel="noopener noreferrer"&gt;250 core and community plugins&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/K4f-fMuAoRY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the project
&lt;/h2&gt;

&lt;p&gt;You can create a new API with a single command.&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;npx create-nx-workspace@latest &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--preset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node-server &lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="c"&gt;# create a server project&lt;/span&gt;
&lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fastify &lt;span class="se"&gt;\ &lt;/span&gt; &lt;span class="c"&gt;# other options are express and koa&lt;/span&gt;
&lt;span class="nt"&gt;--docker&lt;/span&gt;               &lt;span class="c"&gt;# we'll touch on this later on&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;To run the server in dev-mode, use &lt;code&gt;npx nx serve&lt;/code&gt; (aliased to &lt;code&gt;npm start&lt;/code&gt;), and you should see the server starting at port 3000.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl http://localhost:3000
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"message"&lt;/span&gt;:&lt;span class="s2"&gt;"Hello API"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;A couple of notable files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;src/main.ts&lt;/code&gt; file is responsible for starting the Fastify server and registering plugins.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;src/app/app.ts&lt;/code&gt; file is the app plugin that provides an initial endpoint at &lt;code&gt;/&lt;/code&gt; that replies with &lt;code&gt;{"message": "Hello API"}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you edit the source code, the server will reload. You can pass &lt;code&gt;--no-watch&lt;/code&gt; to disable this behavior.&lt;/p&gt;
&lt;h2&gt;
  
  
  Running tests
&lt;/h2&gt;

&lt;p&gt;In additional to generating the source code, Nx will also create two test suites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unit tests via &lt;code&gt;npx nx test&lt;/code&gt; (aliased to &lt;code&gt;npm run test&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;E2E tests via &lt;code&gt;npx nx e2e e2e&lt;/code&gt; (aliased to &lt;code&gt;npm run e2e&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unit tests take advantage of Fastify’s plugin architecture, and allows you to test each plugin in isolation. It runs using &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt;, which is the most popular test runner in Node.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// src/app/app.spec.ts&lt;/span&gt;
&lt;span class="c1"&gt;// This file is generated by Nx.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Fastify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FastifyInstance&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;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;app&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET /&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FastifyInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fastify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should respond with a message&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&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;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello API&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;The E2E tests run against the actual server (with all plugins registered), which gives better real-world guarantees.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;serve&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;background&lt;/span&gt;
&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;e2e&lt;/span&gt; &lt;span class="nx"&gt;e2e&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="nx"&gt;suite&lt;/span&gt;
&lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;✓&lt;/span&gt; &lt;span class="nx"&gt;should&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nf"&gt;message &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;Test&lt;/span&gt; &lt;span class="nx"&gt;Suites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;
&lt;span class="nx"&gt;Tests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;
&lt;span class="nx"&gt;Snapshots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;
&lt;span class="nx"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="mf"&gt;0.429&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;
&lt;span class="nx"&gt;Ran&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="nx"&gt;suites&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;Tearing&lt;/span&gt; &lt;span class="nx"&gt;down&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

 &lt;span class="err"&gt;———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————&lt;/span&gt;

 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="nx"&gt;NX&lt;/span&gt;   &lt;span class="nx"&gt;Successfully&lt;/span&gt; &lt;span class="nx"&gt;ran&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="nx"&gt;e2e&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nf"&gt;e2e &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="nx"&gt;lsof&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;xargs&lt;/span&gt; &lt;span class="nx"&gt;kill&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;stop&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;There are trade-offs between speed versus confidence when it comes to unit versus E2E tests, which is a topic that is out of scope for this article. I think you should do both, but this is a discussion be held with your team. Nx supports both cases out of the box.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building for production using esbuild
&lt;/h2&gt;

&lt;p&gt;Now that we have our production-ready app, let’s examine how Nx handles the build process using &lt;code&gt;[esbuild](https://esbuild.github.io/)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;esbuild&lt;/code&gt; is a bundler written in Go that is extremely fast — it is much faster than other bundlers like webpack and parcel, but that may change in the future as other tools make their own speed improvements.&lt;/p&gt;

&lt;p&gt;When you run the build command, Nx uses &lt;code&gt;esbuild&lt;/code&gt; to generate a self-contained app bundle, which does not require &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;aliased&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;

 &lt;span class="err"&gt;———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————&lt;/span&gt;

 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="nx"&gt;NX&lt;/span&gt;   &lt;span class="nx"&gt;Successfully&lt;/span&gt; &lt;span class="nx"&gt;ran&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nf"&gt;api &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;A cool feature of Nx, is that commands such as &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; are cached if the project (or its dependencies) have not changed. If we run the build a second time, you’ll see it completes in a few milliseconds.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="nx"&gt;outputs&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

 &lt;span class="err"&gt;———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————&lt;/span&gt;

 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="nx"&gt;NX&lt;/span&gt;   &lt;span class="nx"&gt;Successfully&lt;/span&gt; &lt;span class="nx"&gt;ran&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nf"&gt;api &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="nx"&gt;Nx&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="nx"&gt;instead&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;running&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We’ll touch more on the caching when we look at Docker support.&lt;/p&gt;

&lt;p&gt;And now that the server bundle is ready, we can run it.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;level&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1675880059720&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;70605&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hostname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mbp.lan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server listening at http://[::1]:3000&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;level&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1675880059721&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;70605&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hostname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mbp.lan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server listening at http://127.0.0.1:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3000&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You can even run the e2e suite against the production bundle: &lt;code&gt;npx nx e2e e2e&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker support
&lt;/h2&gt;

&lt;p&gt;Recall that we passed the &lt;code&gt;--docker&lt;/code&gt; option when creating the API project. WIth this option, Nx will generate a default &lt;code&gt;Dockerfile&lt;/code&gt; and a &lt;code&gt;docker-build&lt;/code&gt; target.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="c"&gt;# This file is generated by Nx.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Build the docker image with `npx nx docker-build api`.&lt;/span&gt;
&lt;span class="c"&gt;# Tip: Modify "docker-build" options in project.json to change docker build args.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Run the container with `docker run -p 3000:3000 -t api`.&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; docker.io/node:lts-alpine&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; HOST=0.0.0.0&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PORT=3000&lt;/span&gt;

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

&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;--system&lt;/span&gt; api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    adduser &lt;span class="nt"&gt;--system&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; api api

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; dist/api api&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; api:api .

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "node", "api" ]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;To build the image, run &lt;code&gt;npx nx docker-build&lt;/code&gt;. The image copies only the self-contained bundle, so no &lt;code&gt;npm install&lt;/code&gt; at all!&lt;/p&gt;

&lt;p&gt;Nx is smart enough to bundle the app before building the Docker image — because of the &lt;code&gt;dependsOn&lt;/code&gt; configuration in &lt;code&gt;project.json&lt;/code&gt;. You can visualize this dependency with &lt;code&gt;npx nx graph&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnlrgmfg8b8kmkmhxglz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnlrgmfg8b8kmkmhxglz4.png" alt="Nx graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the image is built, we can run it.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

$ docker run -p 3000:3000 -t api
{"level":30,"time":1675880993256,"pid":1,"hostname":"248744de020a","msg":"Server listening at http://0.0.0.0:3000"}
[ ready ] http://0.0.0.0:3000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The server binds to &lt;code&gt;0.0.0.0&lt;/code&gt; so that it can be access from the host machine. You can run curl to verify that it indeed works, or better yet use the E2E test suite (&lt;code&gt;npx nx e2e e2e&lt;/code&gt;)!&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploying the server
&lt;/h2&gt;

&lt;p&gt;There are numerous platforms that we can deploy our app to. I like &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt; since it very easy to deploy all over the world using the CLI, and it comes with good &lt;a href="https://fly.io/docs/languages-and-frameworks/dockerfile/" rel="noopener noreferrer"&gt;Docker support&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you haven’t used Fly before, please follow their &lt;a href="https://fly.io/docs/speedrun/" rel="noopener noreferrer"&gt;short getting started guide&lt;/a&gt; (5-10 mins).&lt;/p&gt;

&lt;p&gt;Once you are ready, let’s configure our project.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

$ fly launch --generate-name --no-deploy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Follow the prompts and a &lt;code&gt;fly.toml&lt;/code&gt; file will be generated, which contains the Fly configuration. We need to update this file with the correct port used by our image.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;

&lt;span class="nn"&gt;[[services]]&lt;/span&gt;
  &lt;span class="py"&gt;http_checks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="py"&gt;internal_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="c"&gt;# Make sure this matches what the app listens on&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Now we can deploy the app.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

$ fly deploy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Fly will log out the monitoring link when the app is successfully deployed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F9u9pnruoq1x3m9bp5ffc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F9u9pnruoq1x3m9bp5ffc.png" alt="Fly dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can open the deployed server using &lt;code&gt;fly open&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Facxdotvmoys3f58b981e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Facxdotvmoys3f58b981e.png" alt="App running in production"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it! Our server is now deployed for the world to use.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post, we saw how easy it is to go from zero code to a deployed server using Nx. Here is a quick summary of the points.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;create-nx-workspace --preset=node-server --framework=fastify --docker&lt;/code&gt; to quickly create a Fastify server project.&lt;/li&gt;
&lt;li&gt;Nx provide both unit test and E2E test suites — &lt;code&gt;npx nx test&lt;/code&gt; and &lt;code&gt;npx nx e2e e2e&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Nx builds the server using esbuild — &lt;code&gt;npx nx build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Docker support is provided out of the box via the &lt;code&gt;--docker&lt;/code&gt; option, and Nx understands that Docker build depends on the app to be bundled. Run it via &lt;code&gt;npx nx docker-build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Deploying to Fly (or other platforms) is easy since we have a Docker image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To learn more about Nx and what else it can do, refer to the &lt;a href="https://nx.dev/getting-started/intro" rel="noopener noreferrer"&gt;intro page&lt;/a&gt; in the docs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🧠 &lt;a href="https://nx.dev" rel="noopener noreferrer"&gt;Nx Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;👩‍💻 &lt;a href="https://github.com/nrwl/nx" rel="noopener noreferrer"&gt;Nx GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;a href="https://go.nrwl.io/join-slack" rel="noopener noreferrer"&gt;Nx Community Slack&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📹 &lt;a href="https://www.youtube.com/@nxdevtools" rel="noopener noreferrer"&gt;Nx Youtube Channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🥚 &lt;a href="https://egghead.io/courses/scale-react-development-with-nx-4038" rel="noopener noreferrer"&gt;Free Egghead course&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🚀 &lt;a href="https://nx.app" rel="noopener noreferrer"&gt;Speed up your CI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, if you liked this, click the ❤️ and make sure to follow &lt;a href="https://twitter.com/jay_soo" rel="noopener noreferrer"&gt;Jack&lt;/a&gt; and &lt;a href="https://twitter.com/nxdevtools" rel="noopener noreferrer"&gt;Nx&lt;/a&gt; on Twitter for more!&lt;/p&gt;


&lt;div class="ltag__tag ltag__tag__id__18643"&gt;
    &lt;div class="ltag__tag__content"&gt;
      &lt;h2&gt;#&lt;a href="https://dev.to/t/nx" class="ltag__tag__link"&gt;nx&lt;/a&gt; Follow
&lt;/h2&gt;
      &lt;div class="ltag__tag__summary"&gt;
        
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>node</category>
      <category>monorepo</category>
      <category>server</category>
      <category>esbuild</category>
    </item>
  </channel>
</rss>
