<?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>Forem: Satomi Nagano / Akikaze1119</title>
    <description>The latest articles on Forem by Satomi Nagano / Akikaze1119 (@stm-akikaze1119).</description>
    <link>https://forem.com/stm-akikaze1119</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%2F2012811%2Fc74be16c-4560-45f1-9ba4-e9fc2e012654.png</url>
      <title>Forem: Satomi Nagano / Akikaze1119</title>
      <link>https://forem.com/stm-akikaze1119</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/stm-akikaze1119"/>
    <language>en</language>
    <item>
      <title>Automatically Send User Data to Database with Clerk OAuth</title>
      <dc:creator>Satomi Nagano / Akikaze1119</dc:creator>
      <pubDate>Mon, 27 Jan 2025 23:06:23 +0000</pubDate>
      <link>https://forem.com/stm-akikaze1119/automatically-send-user-data-to-database-with-clerk-oauth-f0p</link>
      <guid>https://forem.com/stm-akikaze1119/automatically-send-user-data-to-database-with-clerk-oauth-f0p</guid>
      <description>&lt;h2&gt;
  
  
  Key Points
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to use Clerk webhooks.&lt;/li&gt;
&lt;li&gt;Understand how to verify Clerk webhooks.&lt;/li&gt;
&lt;li&gt;Use ngrok to expose a local endpoint for external access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;When using Clerk OAuth for user authentication, detecting new user registrations from the web app can be challenging. To address this, we use Clerk webhooks to automatically send user data to a database upon signup. This article walks through the implementation steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Using Clerk webhooks to send user data to a database upon signup.&lt;/li&gt;
&lt;li&gt;The setup follows &lt;a href="https://clerk.com/docs/webhooks/sync-data" rel="noopener noreferrer"&gt;Clerk’s official documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The database used is Neon (PostgreSQL).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Set Up ngrok
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://clerk.com/docs/webhooks/sync-data" rel="noopener noreferrer"&gt;Clerk’s documentation&lt;/a&gt; recommends using ngrok to allow webhook requests to reach the local app.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.1 Install and Set Up ngrok
&lt;/h4&gt;

&lt;p&gt;Sign up on &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;ngrok's official website&lt;/a&gt; and follow the installation steps provided in the &lt;a href="https://dashboard.ngrok.com/get-started/setup/" rel="noopener noreferrer"&gt;Setup &amp;amp; Installation section&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.2 Obtain an External URL
&lt;/h4&gt;

&lt;p&gt;Start your local development server (&lt;code&gt;npm run dev&lt;/code&gt;), then run&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ngrok http [Port]&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Example: In the case of &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ngrok http 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the &lt;code&gt;Forwarding&lt;/code&gt; URL displayed.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9aaqe18k14pz2qxb6fu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9aaqe18k14pz2qxb6fu2.png" alt="Console screen" width="800" height="49"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  What is ngrok?
&lt;/h4&gt;

&lt;p&gt;Ngrok allows a locally running web app to be temporarily accessible over the internet. In this case, it enables Clerk webhooks to send requests to a local development server.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Configure Clerk Webhooks
&lt;/h3&gt;
&lt;h4&gt;
  
  
  2.1 Access Clerk Dashboard
&lt;/h4&gt;

&lt;p&gt;Go to the &lt;a href="https://dashboard.clerk.com/" rel="noopener noreferrer"&gt;Clerk dashboard&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrmb2mtfsy796uoibuco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrmb2mtfsy796uoibuco.png" alt="Clerk dashboard button" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2.2 Add a Webhook Endpoint
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Webhooks&lt;/strong&gt; tab and click &lt;strong&gt;Add Endpoint&lt;/strong&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4cl44icjtewmh2wbqsm.png" alt="Clerk side menu" width="418" height="788"&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv809et8hu4j1gvaanlkw.png" alt="End point" width="769" height="606"&gt;
&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Endpoint URL&lt;/strong&gt; to the ngrok forwarding URL + &lt;code&gt;/api/webhooks/user&lt;/code&gt; (e.g., &lt;code&gt;https://example.ngrok-free.app/api/webhooks/user&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Add a description if needed.&lt;/li&gt;
&lt;li&gt;Subscribe to the &lt;strong&gt;user.created&lt;/strong&gt; event.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbatj22ml01ondga2gtg6.png" alt="Setup endpoint" width="753" height="954"&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  3. Add Signing Secret to &lt;code&gt;.env.local&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;On the endpoint's settings page, copy the Signing Secret from the webhook settings.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcoqvs6g71yg91j4kru1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcoqvs6g71yg91j4kru1.png" alt="Copy the Signing Secret" width="800" height="723"&gt;&lt;/a&gt;&lt;br&gt;
Add Signing Secret, like &lt;code&gt;SIGNING_SECRET=whsec_123&lt;/code&gt;, to your &lt;code&gt;.env.local&lt;/code&gt; file, which should already include your Clerk API keys and DB URL.&lt;br&gt;
The file should resemble:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL=postgresql://database_url
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_YXdha2Utb3gtODUuY2xlcmsuYWNjb3VudHMuZGV2JA
CLERK_SECRET_KEY=sk_test_5DbmoNJeli74tMRgtzZLBY4SC6gpTLbNGnvAPeWJkE
SIGNING_SECRET=whsec_123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Make the Webhook Route Public
&lt;/h3&gt;

&lt;p&gt;If using &lt;code&gt;clerkMiddleware()&lt;/code&gt;, ensure that &lt;code&gt;/api/webhooks(.*)&lt;/code&gt; is public.  For information on configuring routes, see &lt;a href="https://clerk.com/docs/references/nextjs/clerk-middleware" rel="noopener noreferrer"&gt;the clerkMiddleware() guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Install &lt;code&gt;svix&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Clerk uses &lt;code&gt;svix&lt;/code&gt; to send signed webhook requests. Install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;svix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Create the Webhook API Route
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;/src/app/api/webhooks/user/route.ts&lt;/code&gt; to receive webhook requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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;next/server&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;Pool&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;pg&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;Webhook&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;svix&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;headers&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;next/headers&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;WebhookEvent&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;@clerk/nextjs/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Neon DB connection&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Add to .env&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SIGNING_SECRET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SIGNING_SECRET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;SIGNING_SECRET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error: Please add SIGNING_SECRET from Clerk Dashboard to .env or .env.local&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="c1"&gt;// Create new Svix instance with secret&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGNING_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Get headers&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headerPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;headers&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;svix_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerPayload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svix-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svix_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerPayload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svix-timestamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svix_signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headerPayload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svix-signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// If there are no headers, error out&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;svix_id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;svix_timestamp&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;svix_signature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error: Missing Svix headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get body&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&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;req&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WebhookEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Verify payload with headers&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;evt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;wh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svix-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;svix_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svix-timestamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;svix_timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svix-signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;svix_signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;WebhookEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error: Could not verify webhook:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error: Verification error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Handling the user.created event (modify as needed)&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.created&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// Insert user into Neon DB&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`INSERT INTO users (user_id) VALUES ($1) 
        ON CONFLICT (user_id) DO NOTHING`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="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;User saved to DB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="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;Unhandled event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Webhook Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal Server Error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;h3&gt;
  
  
  7. Test the Webhook
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In the Clerk Webhook settings, go to &lt;strong&gt;Testing&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;user.created&lt;/strong&gt; from &lt;strong&gt;Send event&lt;/strong&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pplbkgzex2q7cfvptyy.png" alt="Testing" width="751" height="504"&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Send Example&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If the request succeeds, it will be marked as &lt;strong&gt;Succeeded&lt;/strong&gt; in &lt;strong&gt;Message Attempts&lt;/strong&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfl514ad6j9kq64cg49v.png" alt="Message Attempts" width="700" height="193"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Therefore your app can automatically register new user information in the database even when using Clerk's OAuth. Please try registering a new user within the app to confirm that it works correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Tips
&lt;/h2&gt;

&lt;p&gt;If you encounter issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check your Middleware configuration&lt;/li&gt;
&lt;li&gt;Check your configuration in the Clerk Dashboard
[For example]
Directory: /src/app*&lt;em&gt;/api/webhooks/user/route.ts&lt;/em&gt;*
Endpoint in Clerk : http://...&lt;strong&gt;/api/webhooks/user&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Test the Route Handler or API Route(following the guide)
1.Create a test route in your application:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl7d74l61bcs7gxmfdua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl7d74l61bcs7gxmfdua.png" alt="Test route" width="800" height="262"&gt;&lt;/a&gt;&lt;br&gt;
▽app/webhooks/test/route.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;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="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;The route is working&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Run your application.&lt;br&gt;
3.Use &lt;code&gt;curl&lt;/code&gt; to test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST
http://localhost:3000/api/webhooks/test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.If you see the {"message":"The route is working"}, then the basic Route Handler is working and ready to build on.&lt;/p&gt;

&lt;h2&gt;
  
  
  User deletion in Clerk
&lt;/h2&gt;

&lt;p&gt;If you want to delete user information on Clerk, you can do so from the "User" tab.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ahdb5oa7ti4k8uybda2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ahdb5oa7ti4k8uybda2.png" alt="User Tab" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add the webhook URL in Clerk with the production domain.&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;Signing Secret&lt;/strong&gt; to production environment variables.&lt;/li&gt;
&lt;li&gt;Deploy your app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clerk webhooks enable real-time detection of new users.&lt;/li&gt;
&lt;li&gt;Ngrok allows local webhook testing by exposing an accessible endpoint.&lt;/li&gt;
&lt;li&gt;Implementing &lt;code&gt;svix&lt;/code&gt; ensures request verification and security.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clerk</category>
      <category>webhook</category>
      <category>nextjs</category>
      <category>ngrok</category>
    </item>
    <item>
      <title>Understanding the Difference Between Imperative and Declarative Programming</title>
      <dc:creator>Satomi Nagano / Akikaze1119</dc:creator>
      <pubDate>Sun, 15 Sep 2024 06:01:44 +0000</pubDate>
      <link>https://forem.com/stm-akikaze1119/understanding-the-difference-between-imperative-and-declarative-programming-1j3m</link>
      <guid>https://forem.com/stm-akikaze1119/understanding-the-difference-between-imperative-and-declarative-programming-1j3m</guid>
      <description>&lt;p&gt;When I first started learning React, my teacher said, "JavaScript is imperative programming, while React is declarative programming." However, this didn’t quite make sense to me at first. So, I decided to break it down to better understand the distinction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing Imperative and Declarative Programming with Pizza🍕
&lt;/h2&gt;

&lt;p&gt;To make it easier to visualize, let’s compare these two approaches to cooking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imperative programming analogy:
&lt;/h3&gt;

&lt;p&gt;It’s like giving a chef step-by-step instructions on how to make a pizza🍕.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxcqu2iqu71znh02qb6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foxcqu2iqu71znh02qb6c.png" alt="imperative example" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Declarative programming analogy:
&lt;/h3&gt;

&lt;p&gt;It’s like ordering a pizza without being concerned about the steps it takes to make the pizza🍕.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1y2fw63p91aa3pv2s46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1y2fw63p91aa3pv2s46.png" alt="declarative example" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Imperative Programming?
&lt;/h2&gt;

&lt;p&gt;Imperative programming is a style where &lt;strong&gt;the developer explicitly defines how to perform a specific task&lt;/strong&gt;. You're writing the steps for how the user interface should be updated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Adding text to an &lt;code&gt;h1&lt;/code&gt; tag in HTML&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const h1Element = document.createElement('h1');
h1Element.textContent = 'Hello, World!';
document.body.appendChild(h1Element);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manually creating the &lt;code&gt;h1 element&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Setting its text content&lt;/li&gt;
&lt;li&gt;Appending it to the page
Every individual step is written. This is a hallmark of imperative programming, where the developer must clearly define what the computer should do and how it should be done.
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39az6vwjkki4g73q7o2g.png" alt="how imperative works" width="800" height="384"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is Declarative Programming?
&lt;/h2&gt;

&lt;p&gt;In contrast, declarative programming focuses on &lt;strong&gt;what you want to achieve&lt;/strong&gt;, without specifying how it should be done. The system handles the details for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Adding text to an h1 tag (using React)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  return (
    &amp;lt;h1&amp;gt;Hello, World!&amp;lt;/h1&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, you’re simply declaring that an &lt;code&gt;h1&lt;/code&gt; element with the text "Hello, World!" should appear. The details of how it gets added to the DOM are handled by React. You only need to specify what you want to happen on the page, making declarative programming much more straightforward and efficient than the imperative approach.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ofzk5j20mxmedt2u7bi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ofzk5j20mxmedt2u7bi.png" alt="how declarative works" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Imperative programming&lt;/strong&gt; involves specifying how things should be done, step by step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declarative programming&lt;/strong&gt; focuses on what you want to accomplish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Declarative libraries like React allow developers to express complex UI logic in simpler, more manageable terms, making the development process faster and more intuitive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference: Next.js Tutorial
&lt;/h3&gt;

&lt;p&gt;The pizza analogy is referenced from &lt;a href="https://nextjs.org/learn/react-foundations/updating-ui-with-javascript#imperative-vs-declarative-programming" rel="noopener noreferrer"&gt;the Next.js tutorial&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Deploy a Full-Stack Application on Vercel</title>
      <dc:creator>Satomi Nagano / Akikaze1119</dc:creator>
      <pubDate>Wed, 04 Sep 2024 22:03:59 +0000</pubDate>
      <link>https://forem.com/stm-akikaze1119/how-to-deploy-a-full-stack-application-on-vercel-reactjs-vite-nodejs-typescript-neon-postgresql-5bnf</link>
      <guid>https://forem.com/stm-akikaze1119/how-to-deploy-a-full-stack-application-on-vercel-reactjs-vite-nodejs-typescript-neon-postgresql-5bnf</guid>
      <description>&lt;p&gt;In this article, I will guide you step by step on how to deploy a full-stack application using Vercel.&lt;/p&gt;

&lt;p&gt;You can check the actual deployed project at the bottom of this article under the reference section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start deploying, please ensure that you meet the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a repository on GitHub, with separate frontend and backend folders&lt;/li&gt;
&lt;li&gt;The connection between the frontend, backend, and the database is confirmed in the testing environment&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploying the Backend to Vercel
&lt;/h2&gt;

&lt;p&gt;Let's start by deploying the backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1. Log in to Vercel
&lt;/h3&gt;

&lt;p&gt;First, &lt;a href="https://vercel.com/login" rel="noopener noreferrer"&gt;log in&lt;/a&gt; to Vercel or &lt;a href="https://vercel.com/signup" rel="noopener noreferrer"&gt;sign up&lt;/a&gt; if you haven't already.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fth9owkt43ofa9ht67b4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fth9owkt43ofa9ht67b4r.png" alt="vercel dashboard" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2. Add a New Project
&lt;/h3&gt;

&lt;p&gt;Click the "Add New..." button in the red box and select "Project" from the dropdown.&lt;/p&gt;

&lt;p&gt;Import an existing project from GitHub. If the target repository is displayed, select the "Import" button in the red box.&lt;/p&gt;

&lt;p&gt;🚨If the target repository is not found, you may need to adjust the GitHub access settings. You can change the settings via the "Adjust GitHub App Permissions" link in the green box.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9xzbi1ibtqiw23k9qyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9xzbi1ibtqiw23k9qyl.png" alt="vercel import" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  How to Adjust GitHub Repository Access Settings
&lt;/h4&gt;

&lt;p&gt;Click the "Adjust GitHub App Permissions" link, select where to import from.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsp1q7qfb1qvib0ndd16d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsp1q7qfb1qvib0ndd16d.png" alt="install vercel" width="571" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the GitHub settings page, select the target repository from the "Repository access" dropdown and click Save. It should now appear in the Import list on Vercel.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xneu6eigt9dgvrvkv6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xneu6eigt9dgvrvkv6m.png" alt="repository access" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3. Configure the Project
&lt;/h3&gt;

&lt;p&gt;Once the import is complete, configure the project.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm31716l16txqd1yaty9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm31716l16txqd1yaty9.png" alt="Confiture project" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Name:&lt;/strong&gt;&lt;br&gt;
It’s a good idea to add "backend" or "server" at the end of the project name.&lt;br&gt;
 (Example: "my-project-backend", "my-project-server", etc.)&lt;/p&gt;

&lt;p&gt;A domain will be created using the name you set here plus ".vercel.app".&lt;br&gt;
(Example: my-project-api.vercel.app, my-project-server.vercel.app, etc.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework Preset:&lt;/strong&gt;&lt;br&gt;
Select "Others" from the dropdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root Directory:&lt;/strong&gt;&lt;br&gt;
Click the "Edit" button and select the backend directory.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpx4k2z25pego53gsmtnk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpx4k2z25pego53gsmtnk.png" alt="root directory" width="800" height="952"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build and Output Settings:&lt;/strong&gt;&lt;br&gt;
No settings are required here, but you can add any if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment Variables:&lt;/strong&gt;&lt;br&gt;
Add the necessary environment variables here. (Note: PORT is not required.)&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5n8h56agox36j733xfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5n8h56agox36j733xfw.png" alt="Environment Variables" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy:&lt;/strong&gt;&lt;br&gt;
Once these settings are complete, click the "Deploy" button.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4. Configure vercel.json
&lt;/h3&gt;

&lt;p&gt;After deployment, add a vercel.json file to the root of the backend folder with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "builds": [
        {
            "src": "*.js",
            "use": "@vercel/node"
        }
    ],
    "routes": [
        {
            "src": "/(.*)",
            "dest": "/"
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ℹ️ &lt;strong&gt;For TypeScript&lt;/strong&gt;, specify it to read the compiled JS files. (In the example below, the TypeScript output directory (&lt;code&gt;"outDir"&lt;/code&gt;) is set to &lt;code&gt;./dist.&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "builds": [
    {
      "src": "dist/server.js",
      "use": "@vercel/node"
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "dist/server.js"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5. Confirm Server Access
&lt;/h3&gt;

&lt;p&gt;Check if you can access the deployed server. You can verify this from the "Domains" URL.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1vwfegmhvbpsrp2qq41.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1vwfegmhvbpsrp2qq41.png" alt="domain link" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the content of the file is displayed or if you see "Cannot GET /" on the page like &lt;a href="https://chatbot-app-api.vercel.app/" rel="noopener noreferrer"&gt;this&lt;/a&gt;, it was successful! 🎉🎉🎉&lt;/p&gt;

&lt;p&gt;🚨 If you get a 404 error, there might be an issue with the &lt;code&gt;vercel.json&lt;/code&gt; settings, so make sure the specified paths are correct.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Froiol8350p5bhzhescm7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Froiol8350p5bhzhescm7.png" alt="404error" width="684" height="444"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploying the Frontend to Vercel
&lt;/h2&gt;

&lt;p&gt;Proceed with the frontend deployment in the same way as the backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; On the Vercel dashboard, click the "Add New..." button and select "Project."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Import the target project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; In the project settings, configure the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Project Name: Set a name like "my-project".&lt;/li&gt;
&lt;li&gt;Framework Preset: Select "Vite" (or "Create React App" if using React only).&lt;/li&gt;
&lt;li&gt;Root Directory: Select the frontend directory, such as client.&lt;/li&gt;
&lt;li&gt;Environment Variables: Add any necessary variables.&lt;/li&gt;
&lt;li&gt;Deploy: Click the "Deploy" button.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Verify by accessing the deployed page. If the site is displayed correctly and the connection to the backend is confirmed, &lt;strong&gt;you're done!&lt;/strong&gt; 🎉🎉🎉&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That’s it for deploying a full-stack application using Vercel. If things don’t work as expected, double-check your settings and environment variables.&lt;/p&gt;
&lt;h2&gt;
  
  
  supplement
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Reference Video
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CNJkX9rYI8U"&gt;
&lt;/iframe&gt;
&lt;br&gt;
This video uses MongoDB, so if you're working on a MERN stack project, it might be more relevant.&lt;/p&gt;

&lt;p&gt;ℹ️ Note: The video mentions &lt;code&gt;"version": 2&lt;/code&gt; in the &lt;code&gt;vercel.json&lt;/code&gt; settings, but &lt;a href="https://vercel.com/docs/projects/project-configuration#version" rel="noopener noreferrer"&gt;the Vercel documentation&lt;/a&gt; advises against using the &lt;code&gt;"version"&lt;/code&gt; property.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deployed Project
&lt;/h3&gt;

&lt;p&gt;The project introduced in this article has been deployed and verified using the following tech stack:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt; &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; + React + TypeScript&lt;br&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Express (Node.js) + TypeScript&lt;br&gt;
&lt;strong&gt;Database:&lt;/strong&gt; &lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt; (PostgreSQL)&lt;br&gt;
Note: You can use other databases like MongoDB as well.&lt;/p&gt;

&lt;p&gt;Repository Structure Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── server             # Backend folder
│   ├── dist           # TypeScript output
│   ├── controllers
│   ├── models
│   ├── routers
│   ├── services
│   └── server.ts
├── client             # Frontend folder
│   ├── src
│   │   ├── components
│   │   ├── utils
│   │   ├── App.tsx
│   │   ├── index.tsx 
│   │   ├── styles
│   │   └── ...
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check out the actual project here: &lt;br&gt;
&lt;a href="https://chatbot-app-vite.vercel.app/" rel="noopener noreferrer"&gt;Chatbot App&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Akikaze1119/chatbot-app-vite" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>react</category>
      <category>node</category>
      <category>vite</category>
    </item>
    <item>
      <title>Understanding Environment Variables in Vite: Why VITE_ Prefix is Important</title>
      <dc:creator>Satomi Nagano / Akikaze1119</dc:creator>
      <pubDate>Sun, 01 Sep 2024 22:59:53 +0000</pubDate>
      <link>https://forem.com/stm-akikaze1119/understanding-environment-variables-in-vite-why-vite-prefix-is-important-5c3k</link>
      <guid>https://forem.com/stm-akikaze1119/understanding-environment-variables-in-vite-why-vite-prefix-is-important-5c3k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When developing a web application with Vite, I encountered an issue where the environment variables I had set up were showing as &lt;code&gt;undefined&lt;/code&gt; in the client-side source code.&lt;br&gt;
The following is a summary of the causes and solutions to this problem.&lt;/p&gt;

&lt;p&gt;.env.local:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;example.tsx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const API_KEY = import.meta.env.API_KEY;
console.log('API KEY: ', API_KEY);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;▽Console&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjx29d2azs423feinujcq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjx29d2azs423feinujcq.png" alt="picture of console.log" width="229" height="113"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Cause and Solution
&lt;/h2&gt;

&lt;p&gt;The issue was that &lt;strong&gt;the environment variables in Vite project required a &lt;code&gt;VITE_&lt;/code&gt; prefix&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;▽Before Fix (&lt;code&gt;.env.local:&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;↓&lt;br&gt;
▽After Fix (&lt;code&gt;.env.local file:&lt;/code&gt;)　←It works😃&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why is the &lt;code&gt;VITE_&lt;/code&gt; Prefix Necessary?
&lt;/h2&gt;

&lt;p&gt;So why does Vite require environment variables to have the &lt;code&gt;VITE_&lt;/code&gt; prefix? There are two main reasons:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Security
&lt;/h3&gt;

&lt;p&gt;The official documentation explains it as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To prevent environment variables from being accidentally exposed to the client, only variables that start with &lt;code&gt;VITE_&lt;/code&gt; are exposed in the processed code by Vite. For example, in the following environment variables:&lt;br&gt;
.env file:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_SOME_KEY=123
DB_PASSWORD=foobar
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Only &lt;code&gt;VITE_SOME_KEY&lt;/code&gt; will be exposed to the client source code as &lt;code&gt;import.meta.env.VITE_SOME_KEY&lt;/code&gt;, while &lt;code&gt;DB_PASSWORD&lt;/code&gt; will not be exposed.&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(import.meta.env.VITE_SOME_KEY); // "123"
console.log(import.meta.env.DB_PASSWORD); // undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Official documentation link: &lt;a href="https://vitejs.dev/guide/env-and-mode#env-files" rel="noopener noreferrer"&gt;Environment Variables&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vite strictly manages the environment variables that can be accessed on the client side by default. If all environment variables were exposed to the client side, &lt;strong&gt;it could pose a significant security risk&lt;/strong&gt;. In particular, it’s crucial to prevent sensitive server-side variables, such as API keys or database credentials, from leaking to the client.&lt;/p&gt;

&lt;p&gt;Therefore, Vite ensures that only variables with the &lt;code&gt;VITE_&lt;/code&gt; prefix are accessible on the client side, preventing the unintended exposure of sensitive information.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Clarity
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;VITE_&lt;/code&gt; prefix indicates which environment variables are intended for client-side use. &lt;strong&gt;This improves code readability and helps prevent the accidental use of variables that should remain private&lt;/strong&gt;, particularly in team development environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supplement
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. What Are Environment Variables?
&lt;/h3&gt;

&lt;p&gt;Let's briefly review what environment variables are. &lt;strong&gt;Environment variables&lt;/strong&gt; are variables used to provide configuration values that an application needs to function. By using environment variables, you can easily switch between different environments (e.g., development, testing, production) without modifying your application’s code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Setting Up Environment Variables in Vite
&lt;/h3&gt;

&lt;p&gt;To use environment variables in Vite, you need to create a &lt;code&gt;.env&lt;/code&gt; file in the root directory of your project and define your variables there. As mentioned earlier, it’s crucial to prefix your variable names with &lt;code&gt;VITE_&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, to set an API key for an external service, your &lt;code&gt;.env&lt;/code&gt; file should look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
(.env file)&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;(example.tsx)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const apiKey = import.meta.env.VITE_API_KEY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. TypeScript Auto-Completion
&lt;/h3&gt;

&lt;p&gt;If you tend to forget details as I do, there’s a way to improve your code's accuracy by using type definitions for &lt;code&gt;import.meta.env&lt;/code&gt;. This provides auto-completion in TypeScript.&lt;/p&gt;

&lt;p&gt;To set this up, simply create a &lt;code&gt;vite-env.d.ts&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; directory and define your environment variables within &lt;code&gt;ImportMetaEnv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Official Documentation: &lt;a href="https://vitejs.dev/guide/env-and-mode#intellisense-for-typescript" rel="noopener noreferrer"&gt;TypeScript Auto-Completion&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When setting environment variables in Vite, it’s essential to prefix the variable names with &lt;code&gt;VITE_&lt;/code&gt;. This practice not only enhances security but also optimizes your application's performance.&lt;/p&gt;

</description>
      <category>vite</category>
      <category>react</category>
      <category>typescript</category>
      <category>fullstack</category>
    </item>
  </channel>
</rss>
