Files
nhost/docs/getting-started/tutorials/nextjs.mdx
David Barroso 69c1ffa766 feat (docs): overhaul structure (#3254)
### **PR Type**
Enhancement, Documentation


___

### **Description**
- Restructured docs navigation and content

- Updated links and paths throughout docs

- Refreshed images and examples in guides

- Added new content for AI, Auth, and Run


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>15
files</summary><table>
<tr>
<td><strong>docs.json</strong><dd><code>Restructure navigation and add
new sections</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-873ce17c654718debe2fe308a2f2279bde8663686423c51f97fab2dd0722b8d9">+616/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>welcome.mdx</strong><dd><code>Add new welcome page with
getting started links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b35cb8e6a6201730c2d95103d1275186d72e727686bfd6470256c0c30137a761">+65/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new getting started
overview page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-8c9b35da559a5de5fe14ee078573e8d487453e26ed760c03ffd7f0ad476ca24d">+88/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new products overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-745a45fa3dbe67784dd921e50865c7ef33fdc6488cff1ccc75d9db524799d8b3">+81/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new platform overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-63ed954170e482e58b02938bcf8ab3c5b9b76b1a37b23b521cd88de2685ab566">+46/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Update AI overview with new
content and links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e36c2139a3deb3ca81742e73df8ce981aa4502fcb3713832636088eda8f120fd">+10/-10</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new Auth overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-fcb8a858a73ee17bb801d63453716d58b940d7b1e51f48c5fb184e34971866f2">+49/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Update Database overview with
new content</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-542ffbd4d75869cef7479dbc59a2c7c67272879b4f219488193794567b545351">+8/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Update Run overview with new
content and links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ca49842af7e87c264e3ce8c19f4df657890fa0965cc188dbffafcd6ced1c526c">+11/-11</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>overview.mdx</strong><dd><code>Add new Cloud overview
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-32f53230fbf8b84f6a60dbf37568f8a4ea4bcab6f2e00e4357cd3b7f4c50cb55">+70/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>style.css</strong><dd><code>Add new styles for welcome
page</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4dde236d1a1b6f7a24be281ce9e8212368612d66a631fa592bfe18653f57c601">+80/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>echo.ts</strong><dd><code>Add echo function
example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-95b428813572cd2a2abcaf0c6e243622d757860c22f170c82126e5d2cbb269f0">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>email-confirm-change.tsx</strong><dd><code>Add email confirm
change template</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-34aea348d369ef146295ec5c36c6df0fde8262277b93b98d7d9f4633092dc195">+129/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>signin-passwordless.tsx</strong><dd><code>Add signin
passwordless email template</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2d67959219d5979cf79921d4e8a86e16cceb46cd1e909a1783b68d27a85a0998">+127/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>email-verify.tsx</strong><dd><code>Add email verify
template</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-139c6d5e04e5f6d2ce2c8e08a513a9830752fd9baff2aab415c9e34b0cee9918">+127/-0</a>&nbsp;
</td>

</tr>
</table></details></td></tr><tr><td><strong>Configuration
changes</strong></td><td><details><summary>2 files</summary><table>
<tr>
<td><strong>docker-compose.yaml</strong><dd><code>Update Docker Compose
configuration</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-47a924f5ea105a2a42b2c421901d43cf1f834a94be0c2f2f868d29dd8990b060">+481/-174</a></td>

</tr>

<tr>
<td><strong>.env.example</strong><dd><code>Update environment variables
example</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-08ca7f9ad9d499c71a30703d1bb00c4c599646480cfcc311972bfaa654530c45">+13/-25</a>&nbsp;
</td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>README.md</strong><dd><code>Update Docker Compose example
README</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-34955300bc0ac9daa466c28e7aa59683b9b0c89e16344cf0544772acfb971b8f">+184/-23</a></td>

</tr>

<tr>
<td><strong>README.md</strong><dd><code>Update main README with new doc
links</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5">+14/-14</a>&nbsp;
</td>

</tr>
</table></details></td></tr><tr><td><strong>Additional
files</strong></td><td><details><summary>101 files</summary><table>
<tr>
  <td><strong>CONTRIBUTING.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DEVELOPERS.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-bd017515eb79a7fb7569b1d15e8963ea380123d4fdf779978dd4b3ab7500fd10">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>README.md</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-c15729e6c35a283a4b0eda60a991303b6c36c03903ba42dbf832bb8d0daa1a1a">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AuthenticatedLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2d69ccffd267658f76d77a864cdece93fc222e08f6025955795fc6f4697f60e7">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>docs.json</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ba8b2e40409d3782ac444d6c60d7f478772311cb211acd1c24c791937e47f1c6">+7/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SubscriptionPlan.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2a5f070869055286b669e382b18d656935752803b9a1ef13390ac028c2a48ac4">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SettingsLayout.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-aa21cda513a125d8cefc5e7b5e1c755128aa904657350abf0ce1cde21e27ca75">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AllowedEmailSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f4b2730b26266319aa6e705012da5bd20774881bc473411bd8b1619bbd0646d1">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AllowedRedirectURLsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5c4c3714c99421265e1c35dd4300423407f758555eab0622d1f3bf12e7eb13ce">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>AppleProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2e75c4eada80cf228714593e2cd315108b5d10ff7f20bd91e8bc884f571f6f85">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>BlockedEmailSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3a99b1db51b5654043151df4d77ad1ec369dd6d475e3261f80bb52e55dd81296">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ClientURLSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-fd60e1f63909e5cf5a57ca7cb9eb5c8577683b638e94185cc840ce8fc6ad0d39">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DisableNewUsersSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-60f6b3603e0467216d9633f4f92879a37416e202b18f0a4da0171332492fb6cf">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DisableSignUpsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-13b3734c8b8aed2e159affbfc9997846e85e2096e739479c72a09e9101d31faf">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DiscordProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-640c83d25085fd13cac559d4b567e2b14f0ef77e003d3b0a6fd4c35b2b5177f9">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>EmailAndPasswordSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b4c8b368defc138ebbf777af773d0a98d00f7130e4f795b0fd83cf934bbf9a4a">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>FacebookProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5103b8085b43ba8f884429a70076ac8707a1510f06d62b5bf5bd08380ef4385c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GitHubProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-438abe40d1c5ea84110c526038042a65d4c960a87f0371c23fc5d493350c5bd7">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GoogleProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3c17bcfb21f6d2066f4727df5d059cfe871a5e1cf5efede5fcdf97d86ce17dbd">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GravatarSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e6d30e32ab062fd6060282190a4b28d86cd7aaf1a08fe3090056759ea43cfc02">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>LinkedInProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-1efc0012f8c04ff4d54a29d20c0bc81422bcb5d689f4141c52179d7e8c054a7f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MFASettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-edb42fdfa300aae0bea103b9b4cc379e3d5c49ed00646a30673473660982904f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MagicLinkSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d698ac461b405af3109f38cf74a81eb919193c28a62fa8abda7f62ba573a38e8">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SMSSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-beffd7762c6b4f12ba0edd9e524fe07c33062f5d8c12d3783ae2bb42e1380f64">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SpotifyProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-93ba8b83aa965db9730f5f4aef9da2db8279a924a3812fc9e6f880173fa4235c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>TwitchProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-0f30d19f5b40424b59a85450a33f870a1a3e7b844e36e2ff7a92ce6c35a441c1">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>WebAuthnSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d34c84f3b66fa2b843540e1829d3c827e38c46d5e663b8dcad11dac964a34080">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>WorkOsProviderSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f0cd2c2e6badf59f882d564bf06617345cb4243bc699af4d02420ec2aefb166e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PointInTimeBackupInfo.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-35be453f6605231bcee5b7f7f78564eb7aa2be723f5169509f9dddfe84477fe6">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DatabasePiTRSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-7a638c446af8419249770dc8da1ea522f950163b1d0045020927216c38db8cec">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>EnvironmentVariableSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-621bb42cb9fe0a763d30e738ab075af2784e8538e5ed7ac6ff1aa132d1a38042">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>SystemEnvironmentVariableSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b952daa2a34e49a14c5a471477fa2d50583091e420d88a3b941503b092d18e5c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>EditRepositoryAndBranchSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e19e36c0830816cdd4d73cd058b91295bbfcbe65c37c36fa9a87e9c1f2e3b7ef">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>BaseDirectorySettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-50bcccdf949a19ce69fa86acdd63b5291fa2beaba07191a62c87d40ea5b94e88">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>DeploymentBranchSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d8fc80cc734f593c686f873536856bf9103efb1115ca865709bbeb7bd940895e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>GitConnectionSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9e7a97afc3500aa2f4b28bdf4acb135925d92a6a595e16a3808b0b90ecc6be58">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>JWTSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4bc7ce8b3f6e45940e5137c199d24b7a62cf3f804bf9c51b34a5f1168567ef25">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ContactPointsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-50a024995bad7b420fd717104a1584009e9fa44c508889dd125155f33d99f48e">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MetricsSMTPSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-db01779fdfdece601aa83a1a2c256e65514602344a8556afd5832d32e465bc65">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>MetricsSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-957bb404fee8d18aa45af9e878837d311b69d9805ac16fe8d2c0e9d3b431e906">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>features.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-036778e07a1cdf33b7d90d8110f75338f8cd6870cc68bb75cff0c880318cd92d">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>frameworks.ts</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3833ff9ca6b5f1020384672b9de38149de400c57beaeb65ea255475ba8ce7da3">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PermissionVariableSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ffbd1a0083e64318b68922362b6392090e24facc2a6476dc31e54e988a7599f6">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ResourcesFormFooter.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-035d56050da913a9ab98c730bb88b34c734149053674204b86bd798d79f81371">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ServiceResourcesFormFragment.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9b9bf7e4f4e4dd34502e1b636c9f9aabbb20defe43595a79aa7e3f7d89750029">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>RoleSettings.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4cd13b62487b2de616d26d895ce4bb3afc7380abf9f3831ef2b949d073802a1f">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ComputeFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b5600bae05b535d54dc04b2a847b6402b10575efd87a0e7098796f0f9ae96d51">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>HealthCheckFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9287c48c51c8a48a4b4aedcdc195cd9c8c79d3b3e2072765608081bc341f7fba">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>ImageField.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6f618d85f2ca9a85b2a754f45e7b7e7803317be7e5dfd0e05bbee87c5bd1f116">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>PortsFormSection.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-75c4254c31fe6addb187b5d122dd1fa171c1a8875c0152a6c1b2a05257c61d4c">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>custom-domains.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e35b13396a4aa0b96e35dd7a0b1a27d188c0d45fe20cbda99e2fd59b83da5574">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>rate-limiting.tsx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f31e44eb689a0e65e60f6eb2701f7adf283582fa5014c8727dc4922ecbd8c657">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>snippet-example.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5fdce31e426151efa036ecdc78f6842c3bcd644a3d7658b1c753ee80c55d3cc8">+0/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>coc.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-dc80329f722e73bc46ee76902de782b4f696a4be0224658cbbb0a70127cb7627">+128/-0</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>getting-involved.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4c15a93e9b63664bed77a875378d805efc8dc787bc0e1d6a6f413a376c5e6983">+57/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>commands.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2053eb5138f4c468b9aa94e6fd7302ad2f577839be107741f265ae1b2d9bfcaa">+0/-158</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>getting-started.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-05cc8d760dce63f257bee91e9c0293424a63e0ed210d26c7bca78bc3a3d5d763">+0/-87</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-dfcca51e047037e649bbf76e68ab3aa9161a85c1bd25cf385acc5e764bea0cd3">+0/-32</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>nextjs.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-291e724f8e8aadb8d126a30590af172b9b82fe187407c83cfc0673d76efd1188">+3/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>react.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-fdf7ec55eee7c46bd8f83f8bf10066a136d21181bd6a04d513ae4c3bfaec1dc5">+7/-21</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>reactnative.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-bac475908ec022811c05fccec3d0eae805b25419b65a5d2537d70c606415d586">+14/-28</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>vue.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-1fee09fc68c4d33cea15dcb726c3e3671fdfbfc605a1751337f685f3cf851ca5">+3/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>nextjs.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-a5210d45e7d33a57d43078dbe2a2ccbf0667b157291fd92c3986092d7d33ab9c">+10/-11</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>react.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6f5adda9f7b29d98c68cab6ec754c0bac501666a49dd635ee830789e2c812b68">+9/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>vue.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f6c4215fa6909fd3accebe0691a7364d17befb8ef90da5a4aeaee83d598c0540">+9/-9</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3ca431109466557ec1ba7fbd4cb01fa0ad6316e3a9a2fe9c4a849b2760cc7613">+0/-115</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2a040923190b20dd4aa651b3cae8a7be263e7c5d014a71e9f27d628fa7404c08">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>getting-started.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f5ce74103419f39f4217dd75f3e89517779c94615558ae726ae1b4519328a939">+0/-35</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>diagrams.txt</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5f90e86736e92ab8b695c8cad8bd1d65d2be49609da7e693957bad0e238e563e">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mermaidjs</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e68718f71eddf030085b739d48f6067bbb15f2421256ff27620d00f022b0c710">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>sequence.mermaid</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-cec810243251bf77934d8689d65f3e7d33f7632decf51e5eb7115b17042c11d9">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>introduction.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-0166b0574213b999964155797259928739a25e0a09d0442bdd14ff8307dcca30">+0/-85</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>mint.json</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-c91a604899dfef4b2494c317f4fd39a7f22b79986095f580399347293d534deb">+0/-560</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>package.json</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-adfa337ce44dc2902621da20152a048dac41878cf3716dfc4cc56d03aa212a56">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>configuration-overlays.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-f94c8434a3810529922d6b73ebd5f348e4f978b973e2959de0c0e45889b914d9">+7/-7</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>local-development.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-29e98b0241b9335e8929e64440664e4be275f3a3965a88d22a3eb80b5034fca1">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>migrate-config.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-0e2b5b8948935d313421790d173d10bb5c1242166f97d87fbf35d2a010d643f1">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>multiple-projects.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-b756a0fa80d9cdbefb538f676c90521bcff5e730498cde0430bfe789475c4e2f">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-18be817b7d51e5caba56718075ae087777f3e3811987257d48949ada0fe96da8">+46/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>seeds.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-94215e4f4b5a3df8c20f0102f5755ecb55b5155d6ddbae30844666e477b496ab">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>subdomain.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3300c8ab184167028e82d2e66932958ac55ebe94fba7d1aa2e45e8180178ea0e">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>billing.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-5a3b0998ad9e2f09c66255dff3651de3c6d7999e8e9c84169481e5e8af95935d">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>compute-resources.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-e2c40097d219e905b83f9e5ea40b19f6b927f846d7834b37a2dbe93dea3f5299">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>custom-domains.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6004c16e12e623eda4d50a3b2e4f8ecbf5c2e1bbc9e5a91a62232e3a35f76a9d">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>environment-variables.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-49e8324f160e8fbe2cfea76adb45de7bbc3da6ca3d64d3a786a0f188c8bec9dc">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>git.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d427ee2887e5cae303ce21a0b08300a82955c0f7f231ecea2ee198b69b0feb8d">+52/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>logs.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-d04ffc497f0eac2496c6bb7d4dfbb49853f35ba380dd45baf2d3239f8a42d569">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>metrics.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-14a13543059bf5d4903769ef3e6a90bb63af5cacc6105a35689ff75936421ea2">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>rate-limits.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-16b5125772f57a495889904938e950431b7b03a886e32241a162554b952db0c1">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>secrets.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4c49bd272574c88f0d475d349c782c4ea24ba5cef97127106ebddde5befe7f4e">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>service-replicas.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-9188cea8fe3017f7732d5c9ed6600ef0147da8e960cff24ac4c6e156b53c4be1">[link]</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>subdomain.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6d4add19495d7514bbaf0d67d9e60cf83b10ca4de6012aaf39dc0e39f3086bc6">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>tls.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-ca2d4657dffa3ca239e06eef76855154feb9b155317c67ff182d79f81aeaa236">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>deployments.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-6fa07c021c9566a75e9aca5efbf0f4708bd9862bb5484bf95cc25ce00f30e853">+0/-38</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>community.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-4f14893ed8d4ebde9be284bec0c27adc760452f8939246a6a65361bfd70760b8">+13/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>dedicated.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-78f989a9a039240f69408cb775632f7494754276051eae98af420dadf096c8cd">+18/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>overview.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-7cc9f04b4559ab62c5104791051ff7d7ad8dea108f1720eb260aa8e68475b0ee">+40/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>support.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2aa4bcb1194ac3857cbb1846e43db4f1a5ebd0d9302e02308ce1502fb8c0a763">+17/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>product.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-3a7c615149cb270f3f59493a817306f87f8771114d1272de085359996e64bef2">+0/-56</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>authentication.mdx</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-1d91de2bc59159b3d47e86967f6ea82c608a10eb277d3fc0b5734f6f19305089">+0/-66</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td><strong>Additional files not shown</strong></td>
<td><a
href="https://github.com/nhost/nhost/pull/3254/files#diff-2f328e4cd8dbe3ad193e49d92bcf045f47a6b72b1e9487d366f6b8288589b4ca"></a></td>

</tr>
</table></details></td></tr></tr></tbody></table>

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>

---------

Co-authored-by: Sumit Saurabh <62152915+sumitsaurabh927@users.noreply.github.com>
Co-authored-by: Nuno Pato <nunopato@gmail.com>
2025-04-01 09:34:27 +02:00

508 lines
13 KiB
Plaintext

---
title: Build a Todo Manager with Next.js
description: Learn how to use Nhost with Next.js
sidebarTitle: Next.js
icon: react
---
In this tutorial, you will build a simple **Todo Manager** application with Nhost and Next.js. Along the way you will interact with the Database, Authentication, and Storage services.
The Todo Manager will allow users to see public `todos` and sign in using a Magic Link to manage their own `todos` with attachments.
<CardGroup cols={3}>
<Card title="Database">
To store todos
</Card>
<Card title="Auth">
To sign in users
</Card>
<Card title="Storage">
To store attachments
</Card>
</CardGroup>
## Setup Nhost Backend
In this section, you will create and setup your first Nhost project.
### Create project
Create a new project in the [Nhost Dashboard](https://app.nhost.io).
Enter the details for your project and wait a couple of minutes while Nhost provisions your backend infrastructure:
- Dedicated PostgreSQL
- Realtime APIs over your data
- Authentication for managing your users
- Storage for handling files
### Create table `todos`
On the project's dashboard, navigate to **Database** and create a new table called `todos`.
![Database](/images/tutorials/todos-react-database.png)
You can either copy and paste the following SQL into the SQL Editor, **Database -> SQL Editor**, or manually create the table by clicking on **New Table**.
<Tabs>
<Tab title="SQL Editor">
Copy and paste the following SQL into the SQL Editor and press **Run**.
<Note>Please make sure to enable **Track this** so that the new table `todos` is available through the auto-generated APIs</Note>
```sql SQL
CREATE TABLE public.todos (
id uuid DEFAULT gen_random_uuid() NOT NULL,
created_at timestamptz DEFAULT now() NOT NULL,
updated_at timestamptz DEFAULT now() NOT NULL,
title text NOT NULL,
completed bool DEFAULT 'false' NOT NULL,
file_id uuid,
user_id uuid NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (file_id) REFERENCES storage.files (id) ON UPDATE SET NULL ON DELETE SET NULL,
FOREIGN KEY (user_id) REFERENCES auth.users (id) ON UPDATE SET NULL ON DELETE SET NULL
);
```
</Tab>
<Tab title="UI">
Click on **New Table** and fill in the details for the `todos` table as shown.
![New Table](/images/tutorials/todos-react-database-new-table.png)
</Tab>
</Tabs>
You should now see a new table called `todos` on the left panel, below **New Table**.
### Set permissions for todos
It's now time to set permission rules for the table you just created. With the table `todos` selected, click on **...**, followed by **Edit Permissions**.
You will set permissions for the `user` role and actions `insert`, `select`, `update`, and `delete`.
<Tabs>
<Tab title="insert">
Click on the right cell for the `user` role and action `insert` and set permissions as follows:
![User Insert](/images/tutorials/todos-react-permissions-insert.png)
</Tab>
<Tab title="select">
Click on the right cell for the `user` role and action `select` and set permissions as follows:
![User Select](/images/tutorials/todos-react-permissions-select.png)
</Tab>
<Tab title="update">
Click on the right cell for the `user` role and action `update` and set permissions as follows:
![User Select](/images/tutorials/todos-react-permissions-update.png)
</Tab>
<Tab title="delete">
Click on the right cell for the `user` role and action `delete` and set permissions as follows:
![User Delete](/images/tutorials/todos-react-permissions-delete.png)
</Tab>
</Tabs>
### Set permissions for files
The `files` table is managed by Nhost and is defined on the `storage` schema. Click on the dropdown right next to `schema.public` and choose `schema.storage`.
With the `files` table selected, click on **...**, followed by **Edit Permissions**.
As before, we want to set permissions for the `user` role and actions `insert`, `select`, `delete`.
<Tabs>
<Tab title="insert">
Click on the right cell for the `user` role and action `insert` and set permissions as follows:
![User Insert](/images/tutorials/todos-react-permissions-files-insert.png)
</Tab>
<Tab title="select">
Click on the right cell for the `user` role and action `select` and set permissions as follows:
![User Select](/images/tutorials/todos-react-permissions-files-select.png)
</Tab>
<Tab title="delete">
Click on the right cell for the `user` role and action `delete` and set permissions as follows:
![User Delete](/images/tutorials/todos-react-permissions-files-delete.png)
</Tab>
</Tabs>
### Enable Sign In with Magic Link
To enable Magic Links, navigate to your project's **Settings -> Sign-In Methods**, toggle Magic Link, and save.
### Recap
<Steps>
<Step title="Nhost project created">
</Step>
<Step title="Database todos created">
</Step>
<Step title="Permissions set for todos and files">
</Step>
<Step title="Magic Link enabled">
</Step>
</Steps>
## Setup Next.js Application
Now that we have Nhost configured, let's move on to setup the React application and the Nhost client.
### Create React Application
Run the following command in your terminal to create a React application using Vite.
```bash Terminal
npx create-next-app@next-14 --no-eslint \
--src-dir \
--no-tailwind \
--import-alias "@/*" \
--js \
--app \
nhost-nextjs
```
### Install Nhost React package
To install Nhost's React package, run the following command.
```bash Terminal
cd nhost-nextjs && npm install @nhost/nextjs
```
#### Configure the Nhost Client
Create a new file with the following code to create a Nhost client. Replace `<SUBDOMAIN>` and `<REGION>` with the values from the project created earlier.
```ts ./src/lib/nhost.ts
import { NhostClient } from "@nhost/nextjs";
export const nhost = new NhostClient({
subdomain: "<SUBDOMAIN>",
region: "<REGION>"
});
```
<Info>The project's `subdomain` and `region` can be found in the Nhost Dashboard under **Project Info**</Info>
### Setup Sign In Component
It is time to setup a new React component to handle the login functionality. Users will be able to sign in using a Magic Link.
Create a new file with the following content:
```js ./src/app/signin.js
"use client";
import { useState } from 'react'
import { useSignInEmailPasswordless } from '@nhost/nextjs'
export default function SignIn() {
const [loading, setLoading] = useState(false)
const [email, setEmail] = useState('')
const { signInEmailPasswordless, error } = useSignInEmailPasswordless()
const handleSignIn = async (event) => {
event.preventDefault()
setLoading(true)
const { error } = await signInEmailPasswordless(email)
if (error) {
console.error({ error })
return
}
setLoading(false)
alert('Magic Link Sent!')
}
return (
<div>
<h1>Todo Manager</h1>
<p>powered by Nhost and React</p>
<form onSubmit={handleSignIn}>
<div>
<input
type="email"
placeholder="Your email"
value={email}
required={true}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<button disabled={loading}>
{loading ? <span>Loading</span> : <span>Send me a Magic Link!</span>}
</button>
</div>
{error && <p>{error.message}</p>}
</form>
</div>
)
}
```
### Setup `Todos` Component
Now that users can sign in, let's move on and create the authenticated page that lists a user's todos and has a form for managing todos with attachments.
```js ./src/app/todos.jsx
"use client";
import { useState, useEffect } from 'react'
import { useNhostClient, useFileUpload } from '@nhost/nextjs'
const deleteTodo = `
mutation($id: uuid!) {
delete_todos_by_pk(id: $id) {
id
}
}
`
const createTodo = `
mutation($title: String!, $file_id: uuid) {
insert_todos_one(object: {title: $title, file_id: $file_id}) {
id
}
}
`
const getTodos = `
query {
todos {
id
title
file_id
completed
}
}
`
export default function Todos() {
const [loading, setLoading] = useState(true)
const [todos, setTodos] = useState([])
const [todoTitle, setTodoTitle] = useState('')
const [todoAttachment, setTodoAttachment] = useState(null)
const [fetchAll, setFetchAll] = useState(false)
const nhostClient = useNhostClient()
const { upload } = useFileUpload()
useEffect(() => {
async function fetchTodos() {
setLoading(true)
const { data, error } = await nhostClient.graphql.request(getTodos)
if (error) {
console.error({ error })
return
}
setTodos(data.todos)
setLoading(false)
}
fetchTodos()
return () => {
setFetchAll(false)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fetchAll])
const handleCreateTodo = async (e) => {
e.preventDefault()
let todo = { title: todoTitle }
if (todoAttachment) {
const { id, error } = await upload({
file: todoAttachment,
name: todoAttachment.name
})
if (error) {
console.error({ error })
return
}
todo.file_id = id
}
const { error } = await nhostClient.graphql.request(createTodo, todo)
if (error) {
console.error({ error })
}
setTodoTitle('')
setTodoAttachment(null)
setFetchAll(true)
}
const handleDeleteTodo = async (id) => {
if (!window.confirm('Are you sure you want to delete this TODO?')) {
return
}
const todo = todos.find((todo) => todo.id === id)
if (todo.file_id) {
await nhostClient.storage.delete({ fileId: todo.file_id })
}
const { error } = await nhostClient.graphql.request(deleteTodo, { id })
if (error) {
console.error({ error })
}
setFetchAll(true)
}
const completeTodo = async (id) => {
const { error } = await nhostClient.graphql.request(
`
mutation($id: uuid!) {
update_todos_by_pk(pk_columns: {id: $id}, _set: {completed: true}) {
completed
}
}
`,
{ id }
)
if (error) {
console.error({ error })
}
setFetchAll(true)
}
const openAttachment = async (todo) => {
const { presignedUrl, error } = await nhostClient.storage.getPresignedUrl({
fileId: todo.file_id
})
if (error) {
console.error({ error })
return
}
window.open(presignedUrl.url, '_blank')
}
return (
<>
<div className="container">
<div className="form-section">
<h2>Add a new TODO</h2>
<form onSubmit={handleCreateTodo}>
<div className="input-group">
<label htmlFor="title">Title</label>
<input
id="title"
type="text"
placeholder="Title"
value={todoTitle}
onChange={(e) => setTodoTitle(e.target.value)}
/>
</div>
<div className="input-group">
<label htmlFor="file">File (optional)</label>
<input id="file" type="file" onChange={(e) => setTodoAttachment(e.target.files[0])} />
</div>
<div className="submit-group">
<button type="submit" disabled={!todoTitle}>
Add Todo
</button>
</div>
</form>
</div>
<div className="todos-section">
{(!loading &&
todos.map((todo) => (
<div className="todo-item" key={todo.id ?? 0}>
<input
type="checkbox"
checked={todo.completed}
disabled={todo.completed}
id={`todo-${todo.id}`}
onChange={() => completeTodo(todo.id)}
/>
{todo.file_id && (
<span>
<a onClick={() => openAttachment(todo)}> Open Attachment</a>
</span>
)}
<label htmlFor={`todo-${todo.id}`} className="todo-title">
{todo.completed && <s>{todo.title}</s>}
{!todo.completed && todo.title}
</label>
<button type="button" onClick={() => handleDeleteTodo(todo.id)}>
Delete
</button>
</div>
))) || (
<div className="todo-item">
<label className="todo-title">Loading...</label>
</div>
)}
</div>
</div>
<div className="sign-out-section">
<button type="button" onClick={() => nhostClient.auth.signOut()}>
Sign Out
</button>
</div>
</>
)
}
```
With both `SignIn` and `Todos` in place, update `./src/App.jsx` to use the new components:
```js ./src/app/App.js
"use client";
import './App.css'
import { NhostProvider } from '@nhost/nextjs'
import { nhost } from '../lib/nhost.js'
import SignIn from './signin'
import Todos from './todos'
import { useEffect, useState } from 'react'
function App() {
const [session, setSession] = useState(null)
useEffect(() => {
setSession(nhost.auth.getSession())
nhost.auth.onAuthStateChanged((_, session) => {
setSession(session)
})
}, [])
return (
<NhostProvider nhost={nhost}>
{session ? <Todos session={session} /> : <SignIn />}
</NhostProvider>
)
}
export default App
```
## The End
Run the Todo Manager with:
```bash Terminal
npm run dev -- --port 3000
```
Open your browser on [localhost:3000](localhost:3000) to see your new application in action.