<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aditya Oberai</title>
    <description>The latest articles on DEV Community by Aditya Oberai (@adityaoberai).</description>
    <link>https://dev.to/adityaoberai</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%2F243926%2F2fd3475e-b238-4ed1-bb9d-4016b3298fdb.jpg</url>
      <title>DEV Community: Aditya Oberai</title>
      <link>https://dev.to/adityaoberai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adityaoberai"/>
    <language>en</language>
    <item>
      <title>Stop Vibe Coding Every Damn Time!</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Mon, 02 Jun 2025 10:00:00 +0000</pubDate>
      <link>https://dev.to/adityaoberai/stop-vibe-coding-every-damn-time-5fj2</link>
      <guid>https://dev.to/adityaoberai/stop-vibe-coding-every-damn-time-5fj2</guid>
      <description>&lt;p&gt;These days, the hype around vibe coding feels limitless. Tools that promise to turn your ideas into apps with nothing more than a chat prompt are everywhere. But back in March this year, I came across a tweet from a developer who discovered that one of those tools, Lovable, was exposing a user's Supabase API key. While it was a publishable API key, it had no permissions or restrictions, and the developer was able to access all the app's data without authentication, just by looking at the public build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is not innovation. This is a security breach waiting to happen.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd052gbaoqhare1rn8o9f.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%2Fd052gbaoqhare1rn8o9f.png" alt="Screenshot of a tweet" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;Screenshot of a tweet
  &lt;/p&gt;

&lt;p&gt;This is what happens when people lean too hard on the vibe. They build software by instinct, skip fundamentals, and trust that the tool knows best. But when you are shipping products that handle real data, real users, and real consequences, vibes alone will not cut it.&lt;/p&gt;

&lt;p&gt;Welcome to 2025, where AI code-generation tools can get you 80 percent of the way there. And yet, &lt;strong&gt;so many early-career developers are building software like they are writing poetry at an open mic.&lt;/strong&gt; No structure, no planning, no understanding. Just vibes. It’s high time we start fixing that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Are Vibe Coding And AI-Assisted Coding The Same Thing?
&lt;/h2&gt;

&lt;p&gt;First, let’s clear the air. Vibe coding is not the same as using an AI assistant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vibe coding is what happens when you build software without understanding how anything works&lt;/strong&gt;, relying entirely on tools to fill in the gaps. You feed ChatGPT a vague prompt, drag in some randomly generated code blocks, wire up a few buttons, and hope it works. You ship without testing. You copy code you don’t understand. You build with vibes, not logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-assisted coding&lt;/strong&gt;, on the other hand, &lt;strong&gt;is intentional&lt;/strong&gt;. You still plan your features. You still understand how your system fits together. You just move faster because you’ve got an AI pair programmer who helps with boilerplate, explains confusing concepts, and suggests things you were going to write anyway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffhr2p7hsw2w2gy246jsl.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%2Ffhr2p7hsw2w2gy246jsl.png" alt="AI-assisted devs vs Vibe coders" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;Image generated using ChatGPT
  &lt;/p&gt;

&lt;p&gt;The difference is in the mindset. &lt;strong&gt;AI-assisted developers are still the architects, while vibe coders hope the house stands because someone else drew the blueprint.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basics Still Matter
&lt;/h2&gt;

&lt;p&gt;Even with AI, you still need to be a developer. If you’re not doing these things, please start today!&lt;/p&gt;

&lt;h3&gt;
  
  
  #1: Learn What You’re Building
&lt;/h3&gt;

&lt;p&gt;Wanting to skip the learning process before building is the number one reason for the sloppily generated code currently available. It is precisely how developers lose all control over what they are building.&lt;/p&gt;

&lt;p&gt;If you’re building an authentication system, you can’t not learn what tokens are, how sessions work, and why storing passwords in plaintext is a terrible idea. If you’re calling APIs, you must understand how requests are structured, what status codes mean, and how to handle errors gracefully. If you’re storing data, you should know how relational and NoSQL databases differ, when to use indexes, and what trade-offs come with each schema decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI can help you write the code, but it can’t teach you to care.&lt;/strong&gt; That part is on you.  And in this case, to care is also to control. Every decision you delegate without understanding becomes a potential landmine waiting to explode (maybe not today, but definitely someday!)&lt;/p&gt;

&lt;h3&gt;
  
  
  #2: Pause and Assess
&lt;/h3&gt;

&lt;p&gt;Before you open Cursor, start wiring up a UI, or churning out an API, just pause and ask yourself: &lt;/p&gt;

&lt;p&gt;What am I actually trying to build?&lt;/p&gt;

&lt;p&gt;Can I describe the core flow of this feature out loud or on paper?&lt;/p&gt;

&lt;p&gt;Is there a simpler solution hiding behind the flashy one?&lt;/p&gt;

&lt;p&gt;Every minute spent thinking before you build will save you ten debugging later. That pause could be the difference between launching a feature that works and shipping one that silently breaks user data in production. &lt;strong&gt;Sometimes, the best code is no code&lt;/strong&gt; (or just a well-placed conditional). But you won’t realize that if you rush to prompt before you plan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7kl8jl1aodx0mg1cpea.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%2Ff7kl8jl1aodx0mg1cpea.png" alt="The basics" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;Image generated using ChatGPT
  &lt;/p&gt;

&lt;h3&gt;
  
  
  #3: Plan Before You Code
&lt;/h3&gt;

&lt;p&gt;Design still matters, now more than ever. Start outlining your features, sketching out your user journeys, and writing pseudocode if that helps you structure your logic.&lt;/p&gt;

&lt;p&gt;Even a basic plan, a few bullets on what the function needs to do, can guide your AI assistant to better output. If you just prompt “build me an upload feature”, the results will vary wildly. But if you’ve already planned: “I need to let users upload PDF files up to 10MB, store them in an S3 storage bucket, and tag them by user ID”, now you’ve got a little more clarity than before (and you still need more but hey, it’s a start).&lt;/p&gt;

&lt;p&gt;Think about how data flows through your app, how users interact with it, and where things might break. These are the habits that turn junior developers into senior ones. &lt;strong&gt;AI can write snippets, but it can’t architect systems.&lt;/strong&gt; That’s still your job.&lt;/p&gt;

&lt;h3&gt;
  
  
  #4: Prompt Better
&lt;/h3&gt;

&lt;p&gt;AI is not a mind-reader. Vague prompts get vague answers. And vague answers lead to broken features.&lt;/p&gt;

&lt;p&gt;You have to be specific. Mention your tech stack: React with Express backend, or Python using FastAPI. Define the scope: Only show me the server-side handler, I’ll wire up the frontend. Include constraints: File size should be under 5MB, and use S3-compatible storage. If something doesn’t work, you must refine your prompt instead of blindly retrying. Break down the problem. Iterate like you would with a human teammate.&lt;/p&gt;

&lt;p&gt;And always test what it gives you. Don’t assume it’s correct. Run the code. Read the output. Check for edge cases. The better your prompt, the better your result (and the more you’ll learn in the process). &lt;strong&gt;Prompting well is a skill. The sooner you treat it like one, the faster you grow.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Tools as Collaborators, Not Crutches
&lt;/h2&gt;

&lt;p&gt;AI isn’t magic. It’s a junior developer who works fast but needs direction. So start treating it like one. That means you:&lt;/p&gt;

&lt;p&gt;Review everything it gives you&lt;/p&gt;

&lt;p&gt;Test like it was written by a stranger (because it was)&lt;/p&gt;

&lt;p&gt;Ask it to explain things, but still go read the docs&lt;/p&gt;

&lt;p&gt;You cannot use these tools to avoid thinking, only to move faster after you’ve thought things through. Because &lt;strong&gt;the goal isn’t to ship fast. The goal is to ship things that don’t explode.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI tools are here to stay. And that’s great. But if you’re a developer, especially early in your career, you don’t get to opt out of learning. Not if you want to build things that last. So stop vibe coding every damn time. Pause. Think. Prompt intentionally. Learn constantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code like you mean it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4vphmtzl6defb58qghh.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%2Fu4vphmtzl6defb58qghh.png" alt="Don't ship fast]" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;Image generated using ChatGPT
  &lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>vibecoding</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Improve your Appwrite developer experience with dev keys</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Thu, 22 May 2025 12:42:37 +0000</pubDate>
      <link>https://dev.to/appwrite/improve-your-appwrite-developer-experience-with-dev-keys-347l</link>
      <guid>https://dev.to/appwrite/improve-your-appwrite-developer-experience-with-dev-keys-347l</guid>
      <description>&lt;p&gt;When building applications with Appwrite, developers often need a way to test and debug services repeatedly over short periods. Sometimes, this can become a hassle, as Appwrite enforces strict rate limits on client apps to prevent abuse. Developers needed a way to bypass these rate limits in their test environments and CI/CD workflows to ensure the robustness of their app functionalities.&lt;/p&gt;

&lt;p&gt;And this is the exact problem &lt;strong&gt;dev keys&lt;/strong&gt; are here to solve!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are dev keys?
&lt;/h2&gt;

&lt;p&gt;Dev keys are a type of secret used by Appwrite's client SDKs. They allow the developer to bypass any rate limits enforced by Appwrite and suppress any CORS errors caused by not using a configured hostname. A developer can configure the expiration date of a dev key to any of the three preset options (1 day, 7 days, or 30 days).&lt;/p&gt;

&lt;p&gt;Dev keys should never be used in production environments, as they can make your app more susceptible to abuse and security breaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try out dev keys in an app
&lt;/h2&gt;

&lt;p&gt;To test dev keys, I created a simple demo web app that sends 200 requests to create a new document in an Appwrite database. To set this app up, you must complete the following steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Setup Appwrite project
&lt;/h3&gt;

&lt;p&gt;First, create an &lt;a href="https://cloud.appwrite.io" rel="noopener noreferrer"&gt;Appwrite Cloud&lt;/a&gt; account or &lt;a href="https://appwrite.io/docs/advanced/self-hosting" rel="noopener noreferrer"&gt;self-host Appwrite 1.7&lt;/a&gt;. Create a project (which will lead you to the project overview page) and head to the &lt;strong&gt;Databases&lt;/strong&gt; page from the left sidebar. Create a new database with the ID &lt;code&gt;testDb&lt;/code&gt; and a new collection with the ID &lt;code&gt;testCollection&lt;/code&gt;. Store both of these IDs for future usage. In this collection, add the following attribute:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;number&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Integer&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Then, head to the &lt;strong&gt;Settings&lt;/strong&gt; tab of the collection, scroll down to the &lt;strong&gt;Permissions&lt;/strong&gt; section, and add the following permissions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Create&lt;/th&gt;
&lt;th&gt;Read&lt;/th&gt;
&lt;th&gt;Update&lt;/th&gt;
&lt;th&gt;Delete&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Lastly, return to the project overview page, head to the &lt;strong&gt;Settings&lt;/strong&gt; page from the left sidebar, and copy your &lt;strong&gt;API endpoint&lt;/strong&gt; and &lt;strong&gt;project ID&lt;/strong&gt; for future usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create web app
&lt;/h3&gt;

&lt;p&gt;Next up, we'll create our test app. This will require us to create two files in our working directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index.html&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Dev keys demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Dev keys demo&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Click on this button to add 200 documents to the database in less than 1 minute.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Add documents&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Appwrite Web SDK --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/appwrite@18.1.1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Our app's script --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Appwrite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://&amp;lt;REGION&amp;gt;.cloud.appwrite.io/v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Your API Endpoint&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR_PROJECT_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Your project ID&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Appwrite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Databases&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promises&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testDb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Your database ID&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testCollection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Your collection ID&lt;/span&gt;
        &lt;span class="nx"&gt;Appwrite&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="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promise&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request initiated:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promises&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;If you open the HTML page in your browser and click on the &lt;code&gt;Add documents&lt;/code&gt; button, you will notice numerous errors in the console with the HTTP code &lt;code&gt;429&lt;/code&gt;, as Appwrite's rate limits allow one client to create 120 requests per minute for this API endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create dev key
&lt;/h3&gt;

&lt;p&gt;Head back to your Appwrite project. On the overview page, select the &lt;strong&gt;Dev keys&lt;/strong&gt; tab under the Integrations section and create a new dev key. You can add whatever name and expiry date you like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0sy7w92eqzyhxuv3c1v.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%2Fd0sy7w92eqzyhxuv3c1v.png" alt="Dev key" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating this dev key, head to the &lt;code&gt;app.js&lt;/code&gt; file and update the Appwrite client to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Appwrite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://&amp;lt;REGION&amp;gt;.cloud.appwrite.io/v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR_PROJECT_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDevKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR_DEV_KEY&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Your dev key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Test the app
&lt;/h3&gt;

&lt;p&gt;Reopen the HTML page in your browser. Clicking the &lt;code&gt;Add documents&lt;/code&gt; button will allow all 200 requests to execute successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;And with that, you have successfully tested dev keys! Learn more about Appwrite by visiting the docs and joining the Discord community.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/advanced/platform/dev-keys" rel="noopener noreferrer"&gt;Appwrite dev keys docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite Discord server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>testing</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>How to setup the SvelteKit starter template on Appwrite Sites</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Wed, 21 May 2025 15:08:48 +0000</pubDate>
      <link>https://dev.to/appwrite/how-to-setup-the-sveltekit-starter-template-on-appwrite-sites-2b2k</link>
      <guid>https://dev.to/appwrite/how-to-setup-the-sveltekit-starter-template-on-appwrite-sites-2b2k</guid>
      <description>&lt;p&gt;Building web applications requires both front-end expertise and back-end infrastructure. &lt;a href="https://appwrite.io/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites&lt;/a&gt; simplifies this process by providing a platform for deploying, hosting, and scaling web applications.&lt;/p&gt;

&lt;p&gt;To ease this process even further, Appwrite Sites offers a variety of starter kits for popular frameworks like Next.js, React, Vue, Nuxt, Angular, SvelteKit, and Flutter. In this blog, you will learn how to set up the SvelteKit starter template and deploy it to Appwrite Sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the starter template
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt; is a modern web framework built on top of Svelte that enables fast, server-rendered and client-enhanced web applications with powerful routing, data loading, and deployment features out of the box.&lt;/p&gt;

&lt;p&gt;Appwrite's SvelteKit starter template includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clean, single-page UI&lt;/li&gt;
&lt;li&gt;Integration with Appwrite's SDK&lt;/li&gt;
&lt;li&gt;Pre-configured deployment settings for Appwrite Sites' SSR rendering strategy&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%2Fk6y2b6zoca3lhn25jbzy.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%2Fk6y2b6zoca3lhn25jbzy.png" alt="Deployed app" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the starter template on Appwrite
&lt;/h2&gt;

&lt;p&gt;Firstly, you must head to Appwrite Cloud and &lt;a href="https://cloud.appwrite.io/console/register" rel="noopener noreferrer"&gt;create an account&lt;/a&gt; if you haven't already (or &lt;a href="https://appwrite.io/docs/advanced/self-hosting" rel="noopener noreferrer"&gt;self-host Appwrite 1.7&lt;/a&gt;). Next, create your first project, which will lead you to the project overview page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwlvkdrqtb1wqfrqvnaj.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%2Frwlvkdrqtb1wqfrqvnaj.png" alt="Add platform" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head to the &lt;strong&gt;Sites&lt;/strong&gt; page from the left sidebar, click on the &lt;strong&gt;Create site&lt;/strong&gt; button, and select the &lt;strong&gt;Clone a template&lt;/strong&gt; option. This will take you to the Appwrite Sites templates listing, where you should search &lt;code&gt;Svelte starter&lt;/code&gt; and click on the template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8mcbrztz2qba92vpo2v.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%2Fp8mcbrztz2qba92vpo2v.png" alt="Starter template" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the template, you can choose to connect a GitHub repository now or at a later time. If you choose to connect a repository, ensure you select a production branch (leave the root directory as is). Then, review the preset environment variables, update the domain name if you want, and click on the &lt;strong&gt;Deploy&lt;/strong&gt; button. You can watch the deployment logs as the site is built.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb0bly5xdgp6e4eb1zpy.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%2Fpb0bly5xdgp6e4eb1zpy.png" alt="Deployment logs" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternative method to deploy starter template
&lt;/h3&gt;

&lt;p&gt;As an alternative to the Appwrite console, you can create and deploy websites using the &lt;a href="https://appwrite.io/docs/products/sites/deploy-manually#cli" rel="noopener noreferrer"&gt;Appwrite CLI&lt;/a&gt;. Create your SvelteKit starter using the following shell command and configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init sites
? What would you like to name your site? Svelte starter
? What ID would you like to have &lt;span class="k"&gt;for &lt;/span&gt;your site? unique&lt;span class="o"&gt;()&lt;/span&gt;
? What framework would you like to use? SvelteKit &lt;span class="o"&gt;(&lt;/span&gt;sveltekit&lt;span class="o"&gt;)&lt;/span&gt;
? What specification would you like to use? 0.5 CPU, 512MB RAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then make any edits to the website and deploy it using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite push sites
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test the starter template
&lt;/h2&gt;

&lt;p&gt;After your site has been successfully deployed, Appwrite will show you a &lt;strong&gt;Congratulations&lt;/strong&gt; page. You can then either choose to view the site by clicking on the &lt;strong&gt;Visit site&lt;/strong&gt; button or view the site configuration (deployments, logs, domains, usage, and settings) by clicking on the &lt;strong&gt;Go to dashboard&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl0sm2yub622kgeumj10.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%2Fcl0sm2yub622kgeumj10.png" alt="Congratulations" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;And with that, the SvelteKit starter kit is deployed to Appwrite Sites. You can explore other templates or deploy any other websites you'd like. &lt;/p&gt;

&lt;p&gt;For more information about Appwrite Sites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites product docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites/quick-start/sveltekit" rel="noopener noreferrer"&gt;Quick start to deploy any SvelteKit app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite Discord server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>svelte</category>
      <category>programming</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>How to setup the Nuxt starter template on Appwrite Sites</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Wed, 21 May 2025 13:47:42 +0000</pubDate>
      <link>https://dev.to/appwrite/how-to-setup-the-nuxt-starter-template-on-appwrite-sites-a6g</link>
      <guid>https://dev.to/appwrite/how-to-setup-the-nuxt-starter-template-on-appwrite-sites-a6g</guid>
      <description>&lt;p&gt;Building web applications requires both front-end expertise and back-end infrastructure. &lt;a href="https://appwrite.io/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites&lt;/a&gt; simplifies this process by providing a platform for deploying, hosting, and scaling web applications.&lt;/p&gt;

&lt;p&gt;To ease this process even further, Appwrite Sites offers a variety of starter kits for popular frameworks like Next.js, React, Vue, Nuxt, Angular, SvelteKit, and Flutter. In this blog, you will learn how to set up the Nuxt starter template and deploy it to Appwrite Sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the starter template
&lt;/h2&gt;

&lt;p&gt;Nuxt is a framework built on top of Vue.js that makes it easy to develop server-rendered, statically generated, or single-page applications with features like routing, SEO optimization, and modular architecture out of the box.&lt;/p&gt;

&lt;p&gt;Appwrite's Nuxt starter template includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clean, single-page UI&lt;/li&gt;
&lt;li&gt;Integration with Appwrite's SDK&lt;/li&gt;
&lt;li&gt;Pre-configured deployment settings for Appwrite Sites' SSR rendering strategy&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%2Fgbz9sulm8m4vhla0lbvu.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%2Fgbz9sulm8m4vhla0lbvu.png" alt="Deployed app" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the starter template on Appwrite
&lt;/h2&gt;

&lt;p&gt;Firstly, you must head to Appwrite Cloud and &lt;a href="https://cloud.appwrite.io/console/register" rel="noopener noreferrer"&gt;create an account&lt;/a&gt; if you haven't already (or &lt;a href="https://appwrite.io/docs/advanced/self-hosting" rel="noopener noreferrer"&gt;self-host Appwrite 1.7&lt;/a&gt;). Next, create your first project, which will lead you to the project overview page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpti1kt87m5obad42p8i.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%2Fgpti1kt87m5obad42p8i.png" alt="Add platform" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head to the &lt;strong&gt;Sites&lt;/strong&gt; page from the left sidebar, click on the &lt;strong&gt;Create site&lt;/strong&gt; button, and select the &lt;strong&gt;Clone a template&lt;/strong&gt; option. This will take you to the Appwrite Sites templates listing, where you should search &lt;code&gt;Nuxt starter&lt;/code&gt; and click on the template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyad3mk7484ezk4x7eayt.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%2Fyad3mk7484ezk4x7eayt.png" alt="Starter template" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the template, you can choose to connect a GitHub repository now or at a later time. If you choose to connect a repository, ensure you select a production branch (leave the root directory as is). Then, review the preset environment variables, update the domain name if you want, and click on the &lt;strong&gt;Deploy&lt;/strong&gt; button. You can watch the deployment logs as the site is built.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2r0w4c0sn6nqqgf26ge.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%2Fc2r0w4c0sn6nqqgf26ge.png" alt="Deployment logs" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternative method to deploy starter template
&lt;/h3&gt;

&lt;p&gt;As an alternative to the Appwrite console, you can create and deploy websites using the &lt;a href="https://appwrite.io/docs/products/sites/deploy-manually#cli" rel="noopener noreferrer"&gt;Appwrite CLI&lt;/a&gt;. Create your Nuxt starter using the following shell command and configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init sites
? What would you like to name your site? Nuxt starter
? What ID would you like to have &lt;span class="k"&gt;for &lt;/span&gt;your site? unique&lt;span class="o"&gt;()&lt;/span&gt;
? What framework would you like to use? Nuxt &lt;span class="o"&gt;(&lt;/span&gt;nuxt&lt;span class="o"&gt;)&lt;/span&gt;
? What specification would you like to use? 0.5 CPU, 512MB RAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then make any edits to the website and deploy it using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite push sites
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test the starter template
&lt;/h2&gt;

&lt;p&gt;After your site has been successfully deployed, Appwrite will show you a &lt;strong&gt;Congratulations&lt;/strong&gt; page. You can then either choose to view the site by clicking on the &lt;strong&gt;Visit site&lt;/strong&gt; button or view the site configuration (deployments, logs, domains, usage, and settings) by clicking on the &lt;strong&gt;Go to dashboard&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flokt08ywruf4olvmd8jo.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%2Flokt08ywruf4olvmd8jo.png" alt="Congratulations" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;And with that, the Nuxt starter kit is deployed to Appwrite Sites. You can explore other templates or deploy any other websites you'd like. &lt;/p&gt;

&lt;p&gt;For more information about Appwrite Sites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites product docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites/quick-start/nuxt" rel="noopener noreferrer"&gt;Quick start to deploy any Nuxt app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite Discord server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>nuxt</category>
      <category>programming</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>How to setup the Next.js starter template on Appwrite Sites</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Wed, 21 May 2025 13:10:06 +0000</pubDate>
      <link>https://dev.to/appwrite/how-to-setup-the-nextjs-starter-template-on-appwrite-sites-357k</link>
      <guid>https://dev.to/appwrite/how-to-setup-the-nextjs-starter-template-on-appwrite-sites-357k</guid>
      <description>&lt;p&gt;Building web applications requires both front-end expertise and back-end infrastructure. Appwrite Sites simplifies this process by providing a platform for deploying, hosting, and scaling web applications.&lt;/p&gt;

&lt;p&gt;To ease this process even further, Appwrite Sites offers a variety of starter kits for popular frameworks like Next.js, React, Vue, Nuxt, Angular, SvelteKit, and Flutter. In this blog, you will learn how to set up the Next.js starter template and deploy it to &lt;a href="https://appwrite.io/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the starter template
&lt;/h2&gt;

&lt;p&gt;Next.js is a React framework that enables developers to build fast, scalable web applications with features like server-side rendering, static site generation, and API routes out of the box.&lt;/p&gt;

&lt;p&gt;Appwrite's Next.js starter template includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clean, single-page UI&lt;/li&gt;
&lt;li&gt;Integration with Appwrite's SDK&lt;/li&gt;
&lt;li&gt;Pre-configured deployment settings for Appwrite Sites' SSR rendering strategy&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%2F4cxsqbkptnflqqja493a.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%2F4cxsqbkptnflqqja493a.png" alt="Deployed app" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the starter template on Appwrite
&lt;/h2&gt;

&lt;p&gt;Firstly, you must head to Appwrite Cloud and &lt;a href="https://cloud.appwrite.io/console/register" rel="noopener noreferrer"&gt;create an account&lt;/a&gt; if you haven't already (or &lt;a href="https://appwrite.io/docs/advanced/self-hosting" rel="noopener noreferrer"&gt;self-host Appwrite 1.7&lt;/a&gt;). Next, create your first project, which will lead you to the project overview page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F207jrkbmlnnbunbp0jjr.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%2F207jrkbmlnnbunbp0jjr.png" alt="Add platform" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head to the &lt;strong&gt;Sites&lt;/strong&gt; page from the left sidebar, click on the &lt;strong&gt;Create site&lt;/strong&gt; button, and select the &lt;strong&gt;Clone a template&lt;/strong&gt; option. This will take you to the Appwrite Sites templates listing, where you should search &lt;code&gt;Next.js starter&lt;/code&gt; and click on the template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi22jhtnw3tgbch9mllsw.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%2Fi22jhtnw3tgbch9mllsw.png" alt="Starter template" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the template, you can choose to connect a GitHub repository now or at a later time. If you choose to connect a repository, ensure you select a production branch (leave the root directory as is). Then, review the preset environment variables, update the domain name if you want, and click on the &lt;strong&gt;Deploy&lt;/strong&gt; button. You can watch the deployment logs as the site is built.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvdf7n45d03sqf1f58uf.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%2Fpvdf7n45d03sqf1f58uf.png" alt="Deployment logs" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternative method to deploy starter template
&lt;/h3&gt;

&lt;p&gt;As an alternative to the Appwrite console, you can create and deploy websites using the &lt;a href="https://appwrite.io/docs/products/sites/deploy-manually#cli" rel="noopener noreferrer"&gt;Appwrite CLI&lt;/a&gt;. Create your Next.js starter using the following shell command and configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init sites
? What would you like to name your site? Next.js starter
? What ID would you like to have &lt;span class="k"&gt;for &lt;/span&gt;your site? unique&lt;span class="o"&gt;()&lt;/span&gt;
? What framework would you like to use? Next.js &lt;span class="o"&gt;(&lt;/span&gt;nextjs&lt;span class="o"&gt;)&lt;/span&gt;
? What specification would you like to use? 0.5 CPU, 512MB RAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then make any edits to the website and deploy it using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite push sites
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test the starter template
&lt;/h2&gt;

&lt;p&gt;After your site has been successfully deployed, Appwrite will show you a &lt;strong&gt;Congratulations&lt;/strong&gt; page. You can then either choose to view the site by clicking on the &lt;strong&gt;Visit site&lt;/strong&gt; button or view the site configuration (deployments, logs, domains, usage, and settings) by clicking on the &lt;strong&gt;Go to dashboard&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqvd92jopktavrh9n7zzb.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%2Fqvd92jopktavrh9n7zzb.png" alt="Congratulations" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;And with that, the Next.js starter kit is deployed to Appwrite Sites. You can explore other templates or deploy any other websites you'd like. &lt;/p&gt;

&lt;p&gt;For more information about Appwrite Sites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites product docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites/quick-start/nextjs" rel="noopener noreferrer"&gt;Quick start to deploy any Next.js app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite Discord server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>programming</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>How to setup the Flutter starter template on Appwrite Sites</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Wed, 21 May 2025 13:02:09 +0000</pubDate>
      <link>https://dev.to/appwrite/how-to-setup-the-flutter-starter-template-on-appwrite-sites-1mhe</link>
      <guid>https://dev.to/appwrite/how-to-setup-the-flutter-starter-template-on-appwrite-sites-1mhe</guid>
      <description>&lt;p&gt;Most web hosting platforms don't support Flutter Web out of the box, often forcing developers to jump through hoops just to get their apps online. This lack of native support can make deploying Flutter Web projects unnecessarily complex and time-consuming.&lt;/p&gt;

&lt;p&gt;Appwrite Sites changes that by offering built-in support for Flutter Web, making it easy to host and scale your applications. Alongside Flutter, Appwrite also provides starter kits for popular frameworks like Next.js, React, Vue, Nuxt, Angular, and SvelteKit. In this blog, you'll learn how to set up the Flutter starter template and deploy it to &lt;a href="https://appwrite.io/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the starter template
&lt;/h2&gt;

&lt;p&gt;Flutter Web is a part of the Flutter framework that allows developers to build responsive, high-performance web applications using a single Dart codebase.&lt;/p&gt;

&lt;p&gt;Appwrite's Flutter starter template includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clean, single-page UI&lt;/li&gt;
&lt;li&gt;Integration with Appwrite's SDK&lt;/li&gt;
&lt;li&gt;Pre-configured deployment settings for Appwrite Sites' Static rendering strategy&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%2F1stffwjg5auy145wurgd.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%2F1stffwjg5auy145wurgd.png" alt="Deployed app" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the starter template on Appwrite
&lt;/h2&gt;

&lt;p&gt;Firstly, you must head to Appwrite Cloud and &lt;a href="https://cloud.appwrite.io/console/register" rel="noopener noreferrer"&gt;create an account&lt;/a&gt; if you haven't already (or &lt;a href="https://appwrite.io/docs/advanced/self-hosting" rel="noopener noreferrer"&gt;self-host Appwrite 1.7&lt;/a&gt;). Next, create your first project, which will lead you to the project overview page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zhayousqd87l0ktrh0b.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%2F9zhayousqd87l0ktrh0b.png" alt="Add platform" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head to the &lt;strong&gt;Sites&lt;/strong&gt; page from the left sidebar, click on the &lt;strong&gt;Create site&lt;/strong&gt; button, and select the &lt;strong&gt;Clone a template&lt;/strong&gt; option. This will take you to the Appwrite Sites templates listing, where you should search &lt;code&gt;Flutter starter&lt;/code&gt; and click on the template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg55ov6y6e4zi1aiy5t9n.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%2Fg55ov6y6e4zi1aiy5t9n.png" alt="Starter template" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the template, you can choose to connect a GitHub repository now or at a later time. If you choose to connect a repository, ensure you select a production branch (leave the root directory as is). Then, review the preset environment variables, update the domain name if you want, and click on the &lt;strong&gt;Deploy&lt;/strong&gt; button. You can watch the deployment logs as the site is built.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternative method to deploy starter template
&lt;/h3&gt;

&lt;p&gt;As an alternative to the Appwrite console, you can create and deploy websites using the &lt;a href="https://appwrite.io/docs/products/sites/deploy-manually#cli" rel="noopener noreferrer"&gt;Appwrite CLI&lt;/a&gt;. Create your Flutter starter using the following shell command and configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite init sites
? What would you like to name your site? Flutter starter
? What ID would you like to have &lt;span class="k"&gt;for &lt;/span&gt;your site? unique&lt;span class="o"&gt;()&lt;/span&gt;
? What framework would you like to use? Flutter &lt;span class="o"&gt;(&lt;/span&gt;flutter&lt;span class="o"&gt;)&lt;/span&gt;
? What specification would you like to use? 0.5 CPU, 512MB RAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then make any edits to the website and deploy it using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;appwrite push sites
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test the starter template
&lt;/h2&gt;

&lt;p&gt;After your site has been successfully deployed, Appwrite will show you a &lt;strong&gt;Congratulations&lt;/strong&gt; page. You can then either choose to view the site by clicking on the &lt;strong&gt;Visit site&lt;/strong&gt; button or view the site configuration (deployments, logs, domains, usage, and settings) by clicking on the &lt;strong&gt;Go to dashboard&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswu6d5cr8za639vcsrky.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%2Fswu6d5cr8za639vcsrky.png" alt="Congratulations" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;And with that, the Flutter starter kit is deployed to Appwrite Sites. You can explore other templates or deploy any other websites you'd like. &lt;/p&gt;

&lt;p&gt;For more information about Appwrite Sites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites" rel="noopener noreferrer"&gt;Appwrite Sites product docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/products/sites/quick-start/flutter" rel="noopener noreferrer"&gt;Quick start to deploy any Flutter Web app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite Discord server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>flutter</category>
      <category>programming</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>How You Can Build The Best, Fastest Blog On The Internet</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Mon, 17 Feb 2025 14:35:43 +0000</pubDate>
      <link>https://dev.to/adityaoberai/how-you-can-build-the-best-fastest-blog-on-the-internet-5688</link>
      <guid>https://dev.to/adityaoberai/how-you-can-build-the-best-fastest-blog-on-the-internet-5688</guid>
      <description>&lt;p&gt;It is (almost) a rite of passage for every developer today to develop and host a blog on their own (because we really love to &lt;em&gt;"engineer"&lt;/em&gt; our own solutions, don't we?) In all honesty, developers are so spoilt for choice today with the number of web frameworks, CMS solutions, and other tools available in the market that it has become next to impossible to pick that &lt;em&gt;"one correct solution"&lt;/em&gt; any longer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6syku2lujfexstpox5xt.gif" 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%2F6syku2lujfexstpox5xt.gif" alt="Too many" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, while the &lt;strong&gt;title of this blog is pure clickbait (sorry!)&lt;/strong&gt; and the irony of not publishing this on a self-hosted blog is not lost on me, we do have a legitimate challenge here. Therefore, in this blog, we will discuss how you can build a simple yet highly performant blog site and deploy it on the internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining our requirements
&lt;/h2&gt;

&lt;p&gt;First things first, we must define what we need from this blog site. If I were to host my own blog, I would ideally want the following features at the minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple, consistent experience&lt;/strong&gt; (just one layout works)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy content authoring system&lt;/strong&gt; (ideally, one that allows writing Markdown)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quick load times&lt;/strong&gt; (all content should be pre-rendered)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO-friendly&lt;/strong&gt; (pre-rendering can help here too)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to preview and test&lt;/strong&gt; (should be simple to locally deploy)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple and cheap to deploy&lt;/strong&gt; (pick one of 'n' hosting platforms with GitHub CI/CD available)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these decided, we can now pick a tech stack to build our blog site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the tech stack
&lt;/h2&gt;

&lt;p&gt;Considering the feature set above, I have chosen the following tech stack to build a blog site:&lt;/p&gt;

&lt;p&gt;
  Web framework: &lt;strong&gt;SvelteKit&lt;/strong&gt;
  &lt;p&gt;&lt;a href="https://kit.svelte.dev" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt; is a full-stack framework for building modern web applications using Svelte. It provides file-based routing, multiple rendering methods (including Static Site Generation or SSG), API handling, and other powerful features to help you build your web apps.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Content authoring system: &lt;strong&gt;Markdoc&lt;/strong&gt;
  &lt;p&gt;&lt;a href="https://markdoc.dev/" rel="noopener noreferrer"&gt;Markdoc&lt;/a&gt; is a Markdown-based content authoring framework developed by Stripe. It extends standard Markdown by adding custom tags, components, and validations, making it more powerful for structured content in web applications.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Site hosting: &lt;strong&gt;Azure Static Web Apps&lt;/strong&gt;
  &lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/products/app-service/static" rel="noopener noreferrer"&gt;Azure Static Web Apps&lt;/a&gt; is a fully managed hosting service for static sites and web frameworks like Next.js, Nuxt, and SvelteKit. It provides automatic deployments from GitHub, free SSL, global CDN, and built-in serverless functions support (via Azure Functions).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You can pick a different hosting platform if you like. Azure Static Web Apps is a personal preference. Platform choice will not directly affect the site's functionalities; however, it may affect site reliability and scalability.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing the blog site
&lt;/h2&gt;

&lt;p&gt;Now that we have decided on our site's tech stack, we can start building the blog site. &lt;/p&gt;

&lt;p&gt;
  Step 1: &lt;strong&gt;Create a SvelteKit app&lt;/strong&gt;
  &lt;blockquote&gt;
&lt;p&gt;Pre-requisite: install &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; on your system if you haven't already.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To create a SvelteKit app, you must open your terminal and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx sv create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will lead us to an interactive setup process, where must pick our project directory, template (pick &lt;code&gt;SvelteKit minimal&lt;/code&gt;, type checking, and other configuration settings.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;┌  Welcome to the Svelte CLI! &lt;span class="o"&gt;(&lt;/span&gt;v0.6.21&lt;span class="o"&gt;)&lt;/span&gt;
│
◇  Where would you like your project to be created?
│  blog
│
◇  Which template would you like?
│  SvelteKit minimal
│
◇  Add &lt;span class="nb"&gt;type &lt;/span&gt;checking with Typescript?
│  No
│
◆  Project created
│
◇  What would you like to add to your project? &lt;span class="o"&gt;(&lt;/span&gt;use arrow keys / space bar&lt;span class="o"&gt;)&lt;/span&gt;
│  prettier, eslint
│
◆  Successfully setup add-ons
│
◇  Which package manager &lt;span class="k"&gt;do &lt;/span&gt;you want to &lt;span class="nb"&gt;install &lt;/span&gt;dependencies with?
│  npm
│
◆  Successfully installed dependencies
│
◇  Successfully formatted modified files
│
◇  Project next steps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once that is done, enter your project directory, run the &lt;code&gt;npm install&lt;/code&gt; command, and your minimal SvelteKit app is ready!&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Step 2: &lt;strong&gt;Integrate Markdoc with SvelteKit&lt;/strong&gt;
  &lt;p&gt;To easily integrate Markdoc with SvelteKit, my team member from Appwrite, &lt;a href="https://github.com/torstendittmann" rel="noopener noreferrer"&gt;Torsten Dittmann&lt;/a&gt;, has developed an open-source &lt;a href="https://github.com/TorstenDittmann/svelte-markdoc-preprocess" rel="noopener noreferrer"&gt;NPM package&lt;/a&gt;, &lt;code&gt;svelte-markdoc-preprocess&lt;/code&gt; that acts as a preprocessor and converts Markdoc to Svelte at build time.&lt;/p&gt;

&lt;p&gt;We will install this in our app by running the following command:&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;svelte-markdoc-preprocess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, visit the &lt;code&gt;svelte.config.js&lt;/code&gt; file and update its content:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;adapter&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;@sveltejs/adapter-auto&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;vitePreprocess&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;@sveltejs/vite-plugin-svelte&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;markdoc&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;svelte-markdoc-preprocess&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;preprocess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;vitePreprocess&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;markdoc&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="na"&gt;extensions&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;.markdoc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;kit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will enable the app to use the preprocessor at build time and designate &lt;code&gt;.markdoc&lt;/code&gt; as a valid file extension.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Step 3: &lt;strong&gt;Prepare a Markdoc layout&lt;/strong&gt;
  &lt;p&gt;Next, we must create a Markdoc layout. This will define a common, consistent structure and styling for our blog pages. In the &lt;code&gt;src&lt;/code&gt; directory, create a directory, &lt;code&gt;markdoc&lt;/code&gt;. Within that, create two subdirectories, &lt;code&gt;layouts&lt;/code&gt; and &lt;code&gt;styles&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;layouts&lt;/code&gt; sub-directory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;src/markdoc/layouts&lt;/code&gt; directory, add a file &lt;code&gt;Blog.svelte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../styles/blog.css&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;formatDate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$lib/utils/date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeToRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$props&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;em&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;larr;&lt;/span&gt; Back to blog&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;formatDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;timeToRead&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; mins&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;render&lt;/span&gt; &lt;span class="nf"&gt;children&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;#title&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-between&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;list-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This layout will load any &lt;strong&gt;frontmatter&lt;/strong&gt; (metadata added to a &lt;code&gt;.markdoc&lt;/code&gt; file) from our blogs and allow us to use the information on our rendered page.&lt;/p&gt;

&lt;p&gt;Now, if you were paying close attention, you may have noticed that a non-existent &lt;code&gt;formatDate&lt;/code&gt; function was included in this layout. To make its existence real, create a &lt;code&gt;date.js&lt;/code&gt; file in the &lt;code&gt;src/lib&lt;/code&gt; directory and add the following code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formatDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dt&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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;month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&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;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;short&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;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDate&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;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;month&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;ul&gt;
&lt;li&gt;The &lt;code&gt;styles&lt;/code&gt; sub-directory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;src/markdoc/styles&lt;/code&gt; directory, add a &lt;code&gt;blog.css&lt;/code&gt; file. You can copy the following CSS code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Arial'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f8f9fa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#343a40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#007bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#495057&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.125rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#495057&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#007bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0056b3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;underline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25rem&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#007bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#6c757d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f8f9fa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;pre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#e9ecef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow-x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#343a40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;ol&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.125rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#title&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-between&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;list-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;table&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-collapse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;collapse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ddd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ddd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;th&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f4f4f4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="nd"&gt;:nth-child&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;even&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f9f9f9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.75rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;blockquote&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.125rem&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;blockquote&gt;
&lt;p&gt;Note: This is just a rudimentary stylesheet generated by GitHub Copilot. Please ensure you make any necessary updates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once this is done, revisit the &lt;code&gt;svelte.config.js&lt;/code&gt; file and update it as follows:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;adapter&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;@sveltejs/adapter-auto&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;vitePreprocess&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;@sveltejs/vite-plugin-svelte&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;markdoc&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;svelte-markdoc-preprocess&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Add two new imports&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;dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;join&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;path&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;fileURLToPath&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;url&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;preprocess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;vitePreprocess&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
        &lt;span class="c1"&gt;// Update markdoc configuration to include the layout&lt;/span&gt;
        &lt;span class="nf"&gt;markdoc&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
            &lt;span class="na"&gt;layouts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fileURLToPath&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/markdoc/layouts/Blog.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;extensions&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;.markdoc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;kit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will allow us to use the layout we just created with our blogs. We're now ready to add our first blog.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Step 4: &lt;strong&gt;Add a new blog&lt;/strong&gt;
  &lt;p&gt;To add our first blog, go to the &lt;code&gt;src/routes&lt;/code&gt; directory (home to all pages in a SvelteKit app) and create a new directory, &lt;code&gt;blogs&lt;/code&gt;. This subdirectory will become home to all the blogs that exist on your site. Inside this, create a subdirectory with whatever route you would like your blog to exist on (using &lt;code&gt;my-first-blog&lt;/code&gt; will make the route of this blog &lt;code&gt;/blogs/my-first-blog&lt;/code&gt; on your deployed website). Here, add a file &lt;code&gt;+page.markdoc&lt;/code&gt; and add the following content:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;blog&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Description&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;this&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;blog"&lt;/span&gt;
&lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Aditya Oberai&lt;/span&gt;
&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2025-02-16&lt;/span&gt;
&lt;span class="na"&gt;timeToRead&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;blog&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gu"&gt;## Tersis supplex causa rapida inpatiensque nomen egi&lt;/span&gt;

&lt;span class="gu"&gt;### Et non foret Pallade nec patrium genus&lt;/span&gt;

Lorem markdownum Bacchei vitiantur contulit in corpus ferre aselli Lycei celebrant accipis. In diem! In praestem remittas quicquid ecquis arte: nuda stabant sequens rogantis &lt;span class="gs"&gt;**et dextrae**&lt;/span&gt; serta.
&lt;span class="p"&gt;
-&lt;/span&gt; Sed velut deplorata reperire Iphis et grave
&lt;span class="p"&gt;-&lt;/span&gt; Ingenium credere ignem conciperet numeros cum forti
&lt;span class="p"&gt;-&lt;/span&gt; Retemptat sibi cupido

&lt;span class="gu"&gt;### Bibit Clytiumque merui progenuit medio&lt;/span&gt;

Cornua dat nec; domabile et seraque Siculique alebat sic? Sacra est mediis parentis exire naides non illum morando fecere, nunc o. Manifestam tunc, vix &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;auferat tantum pudor&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;http://fatebere.io/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; radiorum labant deae: illi adfata est; coepisse te. Usum tristis quodque umerumque natam agantur nosti mihi semine quaesitae erat orbem, est. Ante Pleuron clausas, &lt;span class="gs"&gt;**de forte**&lt;/span&gt;, et urbs triste timor sit meruit verti concipias, sit sacra in.
&lt;span class="p"&gt;
1.&lt;/span&gt; Eram est lacu forsitan rapienda
&lt;span class="p"&gt;2.&lt;/span&gt; Post rami
&lt;span class="p"&gt;3.&lt;/span&gt; Res vomentem viscera deposuisse naris quondam simul

&lt;span class="gu"&gt;### Fuerunt versus in spiro dolor etiam&lt;/span&gt;

Ignes corpora canum sucis studio colla lacrimis est umbra speculabar avia dereptis &lt;span class="ge"&gt;*corpore a effugies*&lt;/span&gt; locuti ad terga, et. Docta est, sibi pars corporis senectae domos volandi multifori Idomeneus visum ad Aeolidae lacrimam veni. Pondere &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;parum&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;http://www.atque.com/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; auras in genus laesi demunt &lt;span class="gs"&gt;**tu est in**&lt;/span&gt; votis adopertaque neque, homini dignos. Acris &lt;span class="ge"&gt;*intabescere Tydides vicit*&lt;/span&gt;; surgunt mille possent virum fatetur maiorque tu verba exspirat acumine ferenti nimiumque suis dicenda corporis. Retrahebat et meus precor, committi signis arsit tamen multa post, voluisti videre.
&lt;span class="gt"&gt;
&amp;gt; Pars dispar, sit labori subiecta curvi [horrendis dea](http://cumnomine.net/deos); est. Durat dicta, arduus&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; [sed tamen commisit](http://www.erat.net/mensas-vocant) plangorem, fuit. Murmure&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Tisiphone premit, nobiliumque tamen Thessalidum ante, *non*.&lt;/span&gt;

Posse et lolium. Sint illis, est morte potest gestu &lt;span class="gs"&gt;**novissimus**&lt;/span&gt; heros celebrandaque illic in troia morte: herba quae.

{% table %}
&lt;span class="p"&gt;*&lt;/span&gt; Foo
&lt;span class="p"&gt;*&lt;/span&gt; Bar
&lt;span class="gh"&gt;* Baz
---
&lt;/span&gt;&lt;span class="p"&gt;*&lt;/span&gt;
  &lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;
&lt;/span&gt;  puts "Some code here."
  &lt;span class="p"&gt;```&lt;/span&gt;
&lt;span class="gh"&gt;* Text in a table
---
&lt;/span&gt;&lt;span class="p"&gt;*&lt;/span&gt;
  A "loose" list with

  multiple line items
&lt;span class="p"&gt;*&lt;/span&gt; Test 2
&lt;span class="gh"&gt;* Test 3
---
&lt;/span&gt;&lt;span class="p"&gt;*&lt;/span&gt; Test 1
&lt;span class="p"&gt;*&lt;/span&gt; A cell that spans two columns {% colspan=2 %}
{% /table %}

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Aditya Oberai's Pic&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://oberai.dev/pic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Locally running our app via the command &lt;code&gt;npm run dev&lt;/code&gt; and visiting the route &lt;code&gt;/blogs/my-first-blog&lt;/code&gt; will render the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl18m9ixtyhlg0583k4or.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%2Fl18m9ixtyhlg0583k4or.png" alt="My first blog" width="800" height="1559"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Step 5: &lt;strong&gt;Create a basic landing page with an index of blogs&lt;/strong&gt;
  &lt;p&gt;Now that our blog layout is functional, we must also create a simple landing page. Since each blog site also needs an index of blogs for people to find content they are interested in, that is what we shall build. This will feature a couple of components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;+page.js&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, create a &lt;code&gt;+page.js&lt;/code&gt; file in the &lt;code&gt;src/routes&lt;/code&gt; directory. The &lt;code&gt;+page.js&lt;/code&gt; file will house a load function to fetch the information of all Markdoc-based routes in the &lt;code&gt;./blogs&lt;/code&gt; subdirectory before the page is rendered. Add the following code to the &lt;code&gt;+page.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;base&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$app/paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;load&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;blogsGlob&lt;/span&gt; &lt;span class="o"&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./blogs/**/*.markdoc&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;eager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogsGlob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;postList&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;frontmatter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;postList&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;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/+page.markdoc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;timeToRead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;frontmatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeToRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/blogs/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;postName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;blogs&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;This load function finds all &lt;code&gt;.markdoc&lt;/code&gt; files in the &lt;code&gt;src/routes/blogs&lt;/code&gt; directory, extracts and processes the frontmatter of each blog post, and prepares all the information to make it available as a property in our index page's &lt;code&gt;.svelte&lt;/code&gt; file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;+page.svelte file&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;src/routes&lt;/code&gt; directory, open the &lt;code&gt;+page.svelte&lt;/code&gt; file and replace the code with the following:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;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;formatDate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$lib/utils/date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$props&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Blog Demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A test blog site built with SvelteKit and Markdoc"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Aditya Oberai's Blog&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#each&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blogs&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;blog&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; | &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;formatDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;/each&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50px&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#007bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;list-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#007bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0056b3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;underline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;.date&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.9rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#6c757d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;768px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&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="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Locally running our app via the command &lt;code&gt;npm run dev&lt;/code&gt; and visiting the index page at the route &lt;code&gt;/&lt;/code&gt; will render the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh34plw5rr0a70al4f0k3.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%2Fh34plw5rr0a70al4f0k3.png" alt="Index page" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I added 2 new blogs for representation purposes. All blogs will be listed in descending order of their date of creation.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;/p&gt;

&lt;p&gt;
  Step 6: &lt;strong&gt;Configure pre-rendering&lt;/strong&gt;
  &lt;p&gt;To improve the blog's load times and make it more SEO-friendly, we must pre-render all the pages at build time so that all the pages are simple HTML files.&lt;/p&gt;

&lt;p&gt;To do so, install the SvelteKit &lt;strong&gt;static&lt;/strong&gt; adapter (and remove the &lt;strong&gt;auto&lt;/strong&gt; adapter as it is an unnecessary dependency):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm uninstall @sveltejs/adapter-auto
npm &lt;span class="nb"&gt;install&lt;/span&gt; @sveltejs/adapter-static
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, visit the &lt;code&gt;svelte.config.js&lt;/code&gt; file and edit the adapter import to the following:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- import adapter from '@sveltejs/adapter-auto';
&lt;/span&gt;&lt;span class="gi"&gt;+ import adapter from '@sveltejs/adapter-static';
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Lastly, visit the &lt;code&gt;src/routes&lt;/code&gt; directory, create a &lt;code&gt;+layout.js&lt;/code&gt; file, and add the following code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prerender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will ensure that every single page in the app is pre-rendered as HTML.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At this point, I built our blog app using &lt;code&gt;npm run build&lt;/code&gt; and previewed it to generate a &lt;a href="https://developer.chrome.com/docs/lighthouse/overview" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt; report.&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%2Fvs4ruz182vy8q89yf6pv.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%2Fvs4ruz182vy8q89yf6pv.png" alt="Lighthouse report" width="800" height="421"&gt;&lt;/a&gt;&lt;br&gt;
We received a &lt;strong&gt;100&lt;/strong&gt; in the &lt;strong&gt;Performance&lt;/strong&gt; and &lt;strong&gt;SEO&lt;/strong&gt; categories.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can now push the SvelteKit app to GitHub and are ready to deploy it.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;
  Step 7: &lt;strong&gt;Deploy the blog site&lt;/strong&gt;
  &lt;blockquote&gt;
&lt;p&gt;Pre-requisite: create an &lt;a href="https://azure.com" rel="noopener noreferrer"&gt;Azure&lt;/a&gt; account&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Deploying the blog site on Azure Static Web Apps is fairly simple due to their in-built GitHub integration. Go to the &lt;a href="https://portal.azure.com" rel="noopener noreferrer"&gt;Azure portal&lt;/a&gt;, click on the &lt;strong&gt;Create a resource&lt;/strong&gt; button, search &lt;strong&gt;Static Web App&lt;/strong&gt;, and create a resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07rq622jc7idrwbal9hy.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%2F07rq622jc7idrwbal9hy.png" alt="Azure Static Web App" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select (or create) a resource group, add a name for your web app, select a pricing plan, and connect your GitHub account and repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqmczg091yhxctmj93hr.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%2Fxqmczg091yhxctmj93hr.png" alt="Azure web app setup - Basics tab" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Azure will auto-detect the framework (SvelteKit) and prepare a GitHub Action for you. Leave those settings as default and create the resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fum807wnh75esnwtahftf.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%2Fum807wnh75esnwtahftf.png" alt="Azure created resource" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Don't forget to click on each step and expand to understand what must be done!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And with that, you have built the &lt;em&gt;best, fastest&lt;/em&gt; blog on the internet! If you liked this blog site, please &lt;strong&gt;star it on GitHub&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/adityaoberai" rel="noopener noreferrer"&gt;
        adityaoberai
      &lt;/a&gt; / &lt;a href="https://github.com/adityaoberai/sv-markdoc-demo" rel="noopener noreferrer"&gt;
        sv-markdoc-demo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SvelteKit Markdoc Blog Demo&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;A blog that uses Static Site Generation on SvelteKit and Markdoc to render blogs from Markdown&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Run the following commands in your terminal:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/adityaoberai/sv-markdoc-demo.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; sv-markdoc-demo
npm install
npm run dev&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Add new blog&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;To add a new blog, go to the directory &lt;code&gt;./src/routes/blog&lt;/code&gt;, create a new directory (the name of this directory will act as your endpoint), and add a &lt;code&gt;+page.markdoc&lt;/code&gt; file with content in the following style:&lt;/p&gt;

&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;---
title: Title of the blog
description: Description of the blog
author: Aditya Oberai
date: 2024-12-16
timeToRead: 3
layout: blog
---

&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;Add&lt;/span&gt; &lt;span class="pl-c1"&gt;blog&lt;/span&gt; &lt;span class="pl-c1"&gt;content&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-c1"&gt;Markdown&lt;/span&gt; &lt;span class="pl-c1"&gt;here&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note: Do not edit the &lt;code&gt;layout: blog&lt;/code&gt; field. ALso, the date is in &lt;code&gt;yyyy-mm-dd&lt;/code&gt; format.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/adityaoberai/sv-markdoc-demo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You can also &lt;strong&gt;try out the demo blog&lt;/strong&gt; deployed on Azure Static Web Apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://icy-sand-053890010.4.azurestaticapps.net/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Try out the blog&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Thank you so much for reading this blog, wish you all &lt;strong&gt;happy building&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw39cse1gvy0lt377rg9.gif" 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%2Fhw39cse1gvy0lt377rg9.gif" alt="Have a good day" width="380" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>svelte</category>
      <category>markdown</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Announcing Appwrite’s Hacktoberfest 2024 Hackathon: Build, innovate, and win!</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Tue, 01 Oct 2024 17:15:58 +0000</pubDate>
      <link>https://dev.to/appwrite/announcing-appwrites-hacktoberfest-2024-hackathon-build-innovate-and-win-l27</link>
      <guid>https://dev.to/appwrite/announcing-appwrites-hacktoberfest-2024-hackathon-build-innovate-and-win-l27</guid>
      <description>&lt;p&gt;&lt;a href="https://hacktoberfest.com/" rel="noopener noreferrer"&gt;Hacktoberfest&lt;/a&gt; is almost here, and we’re excited to announce that Appwrite will be hosting our own &lt;strong&gt;Hacktoberfest 2024 Hackathon&lt;/strong&gt;! Whether you're a seasoned developer or just dipping your toes into open-source, this is the perfect opportunity to create something impactful while being part of the global Hacktoberfest movement.&lt;/p&gt;

&lt;p&gt;From &lt;strong&gt;October 1st to October 31st&lt;/strong&gt;, join thousands of developers worldwide as we work together to push the boundaries of creativity and innovation. This year, we’re looking for projects that showcase not only technical skills but also a fresh perspective on the tools and problems that matter most to the developer community.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need to know:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dates&lt;/strong&gt;: The hackathon will run for the entire month of October, kicking off on &lt;strong&gt;October 1st&lt;/strong&gt; and concluding on &lt;strong&gt;October 31st&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team size&lt;/strong&gt;: You can work solo or with a team of up to &lt;strong&gt;4 members&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project requirements&lt;/strong&gt;: Your submission must be a &lt;strong&gt;brand-new project&lt;/strong&gt;. Whether it's a web app, a mobile app, a game, or a tool, we want to see something fresh and innovative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus areas&lt;/strong&gt;: We're looking for projects that highlight creativity and innovation. Don't be afraid to push the envelope and try something out of the ordinary!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prizes&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The top team will each walk away with &lt;a href="https://appwrite.store/products/preorder-the-appwriter" rel="noopener noreferrer"&gt;&lt;strong&gt;The Appwriter&lt;/strong&gt;&lt;/a&gt;, an exclusive award for the best overall project.&lt;/li&gt;
&lt;li&gt;2nd and 3rd-place teams will receive the &lt;strong&gt;Appwrite swag&lt;/strong&gt; &lt;strong&gt;kit.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why join the Appwrite Hackathon?
&lt;/h2&gt;

&lt;p&gt;Aside from being part of one of the most exciting open-source events of the year, this hackathon is your chance to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collaborate&lt;/strong&gt; with like-minded developers across the world.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Showcase your skills&lt;/strong&gt; by building something new and exciting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn and grow&lt;/strong&gt;, whether you’re deepening your knowledge of Appwrite or trying it out for the first time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Win awesome prizes&lt;/strong&gt; and, of course, eternal bragging rights.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&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%2Foyd4tx0h4xm0opd9c936.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%2Foyd4tx0h4xm0opd9c936.png" alt="Prizes" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This Hacktoberfest, we’re focusing on innovation and creativity. Developers who are given the space to experiment and push their boundaries can build extraordinary things. We want to see &lt;strong&gt;your&lt;/strong&gt; ideas come to life! Read this article about &lt;a href="https://appwrite.io/blog/post/hacktoberfest-2023" rel="noopener noreferrer"&gt;hackathon ideation&lt;/a&gt; to get your creative juices flowing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get involved
&lt;/h2&gt;

&lt;p&gt;Gather your team (or get ready to fly solo) and start brainstorming! &lt;/p&gt;

&lt;p&gt;Don’t forget to register your team and project for a chance to win the prizes. &lt;a href="https://apwr.dev/htf24-hackathon" rel="noopener noreferrer"&gt;Registration is open here&lt;/a&gt; from today until October 31st.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Join our Discord server&lt;/a&gt; to keep up with all future Hackathon news, and mark your calendars for the official kickoff on October 1st!&lt;/p&gt;

&lt;p&gt;Get ready to build, innovate, and show the world what you can create. Let’s make Hacktoberfest 2024 unforgettable!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
      <category>appwrite</category>
      <category>programming</category>
    </item>
    <item>
      <title>Twilio Challenge: Language Translator via Twilio Functions, WhatsApp, Appwrite &amp; OpenAI</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Sun, 16 Jun 2024 13:28:03 +0000</pubDate>
      <link>https://dev.to/adityaoberai/twilio-challenge-language-translator-via-twilio-functions-whatsapp-openai-5hmc</link>
      <guid>https://dev.to/adityaoberai/twilio-challenge-language-translator-via-twilio-functions-whatsapp-openai-5hmc</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/twilio"&gt;Twilio Challenge v24.06.12&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;As an avid translator who often faces challenges with different languages when traveling across different countries. To solve my own problem, I wanted to create a simple chatbot that lets me quickly translate text from my preferred language to another, making it so much easier to communicate with other people.&lt;/p&gt;

&lt;p&gt;Therefore, I created an &lt;strong&gt;AI Language Translator&lt;/strong&gt; using the &lt;code&gt;WhatsApp Sandbox&lt;/code&gt; mode in &lt;code&gt;Twilio Programmable Messaging&lt;/code&gt;, &lt;code&gt;Twilio Functions&lt;/code&gt;, &lt;code&gt;Appwrite Database&lt;/code&gt; and &lt;code&gt;OpenAI's GPT-4o API&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Watch how it works
&lt;/h3&gt;

&lt;p&gt;Here is a demo video of the app:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/YPARXF9TXyw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The chatbot uses &lt;strong&gt;Twilio Programmable Messaging (WhatsApp Sandbox)&lt;/strong&gt; and &lt;strong&gt;Twilio Functions&lt;/strong&gt; to communicate with the user. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appwrite Database&lt;/strong&gt; is primarily used to store the state of the user through the conversation, and all conversation data is deleted as soon as the translation is sent to the user. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI's GPT-4o API&lt;/strong&gt; is used to translate the text to the specified language.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Steps to try
&lt;/h3&gt;

&lt;p&gt;You can try it out by scanning the QR Code in the image or by texting the code &lt;code&gt;join trail-has&lt;/code&gt; to the number &lt;code&gt;+14155238886&lt;/code&gt; on WhatsApp.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzeudq96ekpsr3vpyyi1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzeudq96ekpsr3vpyyi1.png" alt="Twilio WhatsApp Sandbox"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that is done, send the message &lt;code&gt;Hello Twilio&lt;/code&gt; to begin using the chatbot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source code
&lt;/h3&gt;

&lt;p&gt;You can also view the source code of the Twilio Function on GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/adityaoberai" rel="noopener noreferrer"&gt;
        adityaoberai
      &lt;/a&gt; / &lt;a href="https://github.com/adityaoberai/language-translator-twilio-function" rel="noopener noreferrer"&gt;
        language-translator-twilio-function
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Twilio function that translates language using GPT-4o and responds through the Twilio Programmable Messaging on WhatsApp
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Twilio Challenge: Language Translator via Twilio Functions, WhatsApp, Appwrite &amp;amp; OpenAI&lt;/h1&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Twilio function that translates language using GPT-4o and responds through the Twilio Programmable Messaging on WhatsApp&lt;/p&gt;

  
    
    

    &lt;span class="m-1"&gt;Screen_Recording_20240617_172845_WhatsApp.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twilio Programmable Messaging (WhatsApp Sandbox)&lt;/strong&gt; and &lt;strong&gt;Twilio Functions&lt;/strong&gt; is used to communicate with the user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appwrite Database&lt;/strong&gt; is used to store the state of the user through the conversation, and all conversation data is deleted as soon as the translation is sent to the user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI's GPT-4o API&lt;/strong&gt; is used to translate the text to the specified language&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/adityaoberai/language-translator-twilio-function" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Twilio and AI
&lt;/h2&gt;

&lt;p&gt;To create this chatbot, I used &lt;strong&gt;OpenAI's GPT-4o API&lt;/strong&gt; in a Twilio Function. This function consumes the text to translate, and the target language based on the user's input and returns the translated text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Twilio Times Two&lt;/code&gt;: The project uses &lt;strong&gt;Twilio Programmable Messaging (WhatsApp Sandbox)&lt;/strong&gt; and &lt;strong&gt;Twilio Functions&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Impactful Innovators&lt;/code&gt;: In a far more interconnected world than ever, a tool that simplifies cross-language communication will help bring people from different cultures closer together.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feedback, Updates, and Testimonials
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;During the process of developing the Twilio Function, I discovered an issue with the max length of environment variables. The issue has already been acknowledged by the Twilio team.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="liquid-comment"&gt;
    &lt;div class="details"&gt;
      &lt;a href="/adityaoberai"&gt;
        &lt;img class="profile-pic" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F243926%2F2fd3475e-b238-4ed1-bb9d-4016b3298fdb.jpg" alt="adityaoberai profile image"&gt;
      &lt;/a&gt;
      &lt;a href="/adityaoberai"&gt;
        &lt;span class="comment-username"&gt;Aditya Oberai&lt;/span&gt;
      &lt;/a&gt;
      &lt;span class="color-base-30 px-2 m:pl-0"&gt;•&lt;/span&gt;

&lt;a href="https://dev.to/adityaoberai/comment/2fpj3" class="comment-date crayons-link crayons-link--secondary fs-s"&gt;
  &lt;time class="date-no-year"&gt;
    Jun 17
  &lt;/time&gt;

&lt;/a&gt;

    &lt;/div&gt;
    &lt;div class="body"&gt;
      &lt;p&gt;Just finished my submission 🥳&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/anthonyjdella"&gt;@anthonyjdella&lt;/a&gt;, I do have some product feedback. When trying out Twilio Functions, I noticed that the max length of environment variables is set to 255 characters. I was using Appwrite Databases as a part of my project, and the API keys happened to be 256 characters in length. This made it somewhat challenging to use environment variables for that purpose. &lt;/p&gt;


    &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;The project is getting real-world usage and positive user feedback publicly!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1803512147663868323-77" src="https://platform.twitter.com/embed/Tweet.html?id=1803512147663868323"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1803512147663868323-77');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1803512147663868323&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>twiliochallenge</category>
      <category>ai</category>
      <category>twilio</category>
    </item>
    <item>
      <title>Rethinking password security: say goodbye to plaintext passwords</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Tue, 02 Apr 2024 10:41:21 +0000</pubDate>
      <link>https://dev.to/appwrite/rethinking-password-security-say-goodbye-to-plaintext-passwords-2hng</link>
      <guid>https://dev.to/appwrite/rethinking-password-security-say-goodbye-to-plaintext-passwords-2hng</guid>
      <description>&lt;p&gt;Recently, we came across a report by &lt;a href="https://www.bleepingcomputer.com/news/security/misconfigured-firebase-instances-leaked-19-million-plaintext-passwords/"&gt;BleepingComputer&lt;/a&gt;, which shared how misconfigured Firebase projects led to the leakage of 19 million plaintext passwords on the public internet. This was primarily caused by missing or incorrectly configured security rules on Firebase instances that consequently permitted read access to databases, resulting in a massive data leak that exposed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Names: 84,221,169&lt;/li&gt;
&lt;li&gt;Emails: 106,266,766&lt;/li&gt;
&lt;li&gt;Phone numbers: 33,559,863&lt;/li&gt;
&lt;li&gt;Passwords: 20,185,831&lt;/li&gt;
&lt;li&gt;Billing info (bank details, invoices, etc.): 27,487,924&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For passwords, the problem was a lot worse because 98% of them, or 19,867,627 to be exact, were in plaintext. While this problem is not inherently a Firebase bug, it does signify a massive lack of understanding around authentication tooling and password security. Therefore, this blog will discuss why plaintext passwords are bad for your security and alternative solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dangers of plain text passwords
&lt;/h2&gt;

&lt;p&gt;Storing passwords in plaintext presents significant security risks and vulnerabilities for both users and organizations. Here are several vital points illustrating why plaintext passwords are bad:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An easy target for hackers&lt;/strong&gt;: Plaintext passwords can be easily read and exploited by anyone who gains unauthorized access to the storage database, making them prime targets for hackers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of confidentiality&lt;/strong&gt;: Storing passwords in plaintext fails to protect the confidentiality of user information. If a security breach occurs, users’ passwords are exposed without any layer of protection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-compliance with security standards&lt;/strong&gt;: Many industry standards and regulations, such as GDPR, PCI DSS, and HIPAA, require that personal data, including passwords, be adequately protected, and storing passwords in plaintext can result in non-compliance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased risk of insider threats&lt;/strong&gt;: Plaintext passwords are vulnerable to external threats and insider threats. Employees with access to the database can view and potentially misuse this information, leading to internal security breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher impact of data breaches&lt;/strong&gt;: When passwords are stored in plaintext, the impact of a data breach is magnified. Attackers can access the compromised system and use the same credentials to attempt access to other services, exploiting the common habit of password reuse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No defense against brute force attacks&lt;/strong&gt;: Plaintext passwords offer no defense against brute force attacks. While hashed passwords can also be vulnerable, hashing makes decoding user passwords a lot more difficult.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Damage to reputation&lt;/strong&gt;: A company found to be storing passwords in plaintext can suffer significant damage to its reputation. Users and clients lose trust in a business that doesn’t prioritize their information’s security.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Alternatives to plaintext passwords
&lt;/h2&gt;

&lt;p&gt;Fortunately, modern authentication systems are built with the drawbacks of plaintext passwords kept in mind. Two major solutions that have been developed to solve this problem are as follows:&lt;/p&gt;

&lt;h3&gt;
  
  
  Password hashing
&lt;/h3&gt;

&lt;p&gt;Password hashing is a security technique that converts a plaintext password into a fixed-size string of characters, which is virtually impossible to reverse. This process uses a hash function to transform the original password, ensuring that even if the data storage is compromised, the actual passwords are not easily deciphered.&lt;/p&gt;

&lt;p&gt;Benefits of password hashing compared to storing passwords in plaintext include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced security&lt;/strong&gt;: Hashed passwords are extremely difficult to reverse-engineer, providing a higher level of security against data theft.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data breach protection&lt;/strong&gt;: In the event of a breach, hashed passwords significantly reduce the risk of passwords being used for unauthorized access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance with standards&lt;/strong&gt;: Hashing passwords helps organizations comply with data protection and privacy regulations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User trust&lt;/strong&gt;: By securing passwords effectively, businesses can maintain and even boost user trust by demonstrating a commitment to privacy and security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mitigation of reuse attacks&lt;/strong&gt;: Hashed passwords make it harder for attackers to use stolen credentials on other sites, reducing the impact of credential reuse attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability and future-proofing&lt;/strong&gt;: Hashing algorithms can be updated and strengthened over time, providing flexibility as security standards evolve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read our &lt;a href="https://appwrite.io/blog/post/password-hashing-algorithms"&gt;blog on password hashing algorithms&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Passwordless authentication
&lt;/h3&gt;

&lt;p&gt;Passwordless authentication eliminates the need for users to create and remember passwords, aiming to enhance both security and user experience. Instead of relying on a traditional password, passwordless methods verify identity through alternative means. This approach can significantly reduce the risk of phishing attacks and password theft, as there’s no password to steal or guess.&lt;/p&gt;

&lt;p&gt;Some common passwordless authentication methods are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Biometric verification&lt;/strong&gt;: Uses unique biological characteristics, such as fingerprints or facial recognition, for identification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Magic links&lt;/strong&gt;: Sends a one-time use URL to the user’s registered email address for login.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-time passwords (OTPs)&lt;/strong&gt;: Generates a single-use code sent via SMS or email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication apps&lt;/strong&gt;: Generates time-based codes or push notifications for user approval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart cards and security tokens&lt;/strong&gt;: Physical devices that the user must possess to gain access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read our &lt;a href="https://appwrite.io/blog/post/improve-ux-passwordless-auth"&gt;blog on passwordless authentication&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Appwrite solves this problem
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://appwrite.io/docs/products/auth"&gt;Appwrite Authentication&lt;/a&gt; makes building secure and robust authentication easy and supports many authentication methods. Currently, the following authentication methods are available on Appwrite to combat plaintext passwords:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email and password login with &lt;code&gt;Argon2id&lt;/code&gt; password hashing&lt;/li&gt;
&lt;li&gt;OTP-based login via SMS and email&lt;/li&gt;
&lt;li&gt;Magic URL login via email&lt;/li&gt;
&lt;li&gt;30+ external OAuth2 providers, including Google, Facebook, GitHub, LinkedIn, and Apple&lt;/li&gt;
&lt;li&gt;JSON Web Token (&lt;a href="https://jwt.io/"&gt;JWT&lt;/a&gt;) creation to extend user authentication to server-side functions&lt;/li&gt;
&lt;li&gt;Custom token login to allow integration with any external authentication solution of your choice&lt;/li&gt;
&lt;li&gt;Two-factor authentication to add an additional layer of security to user accounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, to prevent unauthorized data access, Appwrite features a &lt;a href="https://appwrite.io/docs/advanced/platform/permissions"&gt;robust permissions system&lt;/a&gt; that is thoroughly coupled with Appwrite Authentication. The most significant benefit of Appwrite’s permissions system is that any developer needs to offer read or write access to any user intentionally. No default rule provides open access to your application’s client, and the process of setting permissions is simplified by using Appwrite’s console UI. &lt;/p&gt;

&lt;p&gt;Appwrite also enforces the setting of authorized clients to communicate with an Appwrite project for all supported client platforms (web, Android, Apple, and Flutter). This way, no unauthorized clients can access data, adding an extra layer of protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving forward
&lt;/h2&gt;

&lt;p&gt;No matter what rules and systems any platform provides, combating plaintext passwords is a responsibility shared by all application developers. If you, as a developer, care about the security and privacy of your user accounts and data, you must take the necessary actions to safeguard their authentication information. Appwrite takes this problem very seriously and will continue to add new tools and improve our existing ones to make user authentication simpler and safer for all developers and their users.&lt;/p&gt;

&lt;p&gt;Learn more about Appwrite Authentication through our &lt;a href="https://appwrite.io/docs/products/auth"&gt;docs&lt;/a&gt; and join our &lt;a href="https://appwrite.io/discord"&gt;Discord server&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>appwrite</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Improving user experience with passwordless authentication</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Tue, 02 Apr 2024 10:41:00 +0000</pubDate>
      <link>https://dev.to/appwrite/improving-user-experience-with-passwordless-authentication-2oio</link>
      <guid>https://dev.to/appwrite/improving-user-experience-with-passwordless-authentication-2oio</guid>
      <description>&lt;p&gt;Today, as concerns about security and user convenience only grow with digital activity, traditional password-based authentication systems are becoming a relic of the past. In recent times, we have seen a rise in passwordless systems, which are increasingly seeing adoption in both small and big companies alike, such as Expensify (whose transition was also covered in a Forbes &lt;a href="https://www.forbes.com/sites/quickerbettertech/2023/05/29/on-technology-expensify-forces-passwordless-on-its-users-and-good-for-them/?sh=397a7b017cac"&gt;article&lt;/a&gt; in 2023. A &lt;a href="https://research.esg-global.com/reportaction/SecuringTheIdentityPerimeterReport/Toc"&gt;survey from Enterprise Strategy Group&lt;/a&gt;, a division of TechTarget, in 2022 also revealed that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;31% of respondents picked passwordless authentication as their top identity-related activity&lt;/li&gt;
&lt;li&gt;34% of respondents chose passwordless authentication among their top three identity-related activities&lt;/li&gt;
&lt;li&gt;54% of respondents have started to transition to passwordless authentication&lt;/li&gt;
&lt;li&gt;Of organizations transitioning to passwordless strategies, more than 50% experienced a significant positive impact on risk reduction and improved UX&lt;/li&gt;
&lt;li&gt;Almost two-thirds reported increased efficiency for IT and security teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, in this blog, we'll explore what passwordless authentication is, the drawbacks of conventional methods, and how embracing passwordless solutions can be a game-changer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The drawbacks of traditional password-based systems
&lt;/h2&gt;

&lt;p&gt;As per an &lt;a href="https://blog.lastpass.com/2023/07/pervasive-password-less-protection-the-solution-to-the-compromised-credentials-crisis"&gt;article&lt;/a&gt; by Lastpass, passwords need to be treated like a user experience today because repeated login attempts, forgotten passwords, mandatory password changes, and looking up passwords in a document or notebook only slow employees down and create friction in their workflow. Traditional password systems, despite their ubiquity, come with significant drawbacks, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Password fatigue&lt;/strong&gt;: Users struggle with remembering numerous passwords for different accounts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security risks&lt;/strong&gt;: Weak or reused passwords increase vulnerability to hacking and data breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User inconvenience&lt;/strong&gt;: Managing complex passwords is often cumbersome and frustrating and only causes more fatigue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-consuming&lt;/strong&gt;: Resetting forgotten passwords and managing accounts adds unnecessary steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phishing vulnerabilities&lt;/strong&gt;: Traditional passwords are susceptible to phishing attacks and can open up new attack vectors for a product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited physical security&lt;/strong&gt;: Passwords can be easily observed or stolen, especially in public or shared spaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is passwordless authentication?
&lt;/h2&gt;

&lt;p&gt;Passwordless authentication is exactly what it sounds like – a way to authenticate users without the need for passwords. This paradigm shift in user verification employs methods like &lt;em&gt;passkeys&lt;/em&gt; (fingerprint, facial scans, or screen lock), &lt;em&gt;magic links&lt;/em&gt; (one-time clickable links sent via email or SMS), and &lt;em&gt;one-time passcodes&lt;/em&gt; (OTPs) sent to a user's device. These methods are not only innovative but also align with the natural human tendency to seek convenience and simplicity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of passwordless authentication for user experience
&lt;/h3&gt;

&lt;p&gt;The transition to passwordless authentication brings a myriad of benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced security&lt;/strong&gt;: By eliminating passwords, we inherently reduce the risk of password-related breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved ease of use&lt;/strong&gt;: Users no longer need to remember or manage a plethora of passwords. This simplifies the login process, leading to a more frictionless user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accelerated process&lt;/strong&gt;: Authentication becomes quicker, with just a click or a touch, streamlining the user's journey.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher authentication speed&lt;/strong&gt;: Users can access services faster, without the delay of typing a password.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced user retention&lt;/strong&gt;: Easier login processes can lead to lower user drop-off rates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility for all users&lt;/strong&gt;: Such methods can be more accessible for users who have difficulty remembering passwords or have physical disabilities that make typing challenging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower support costs&lt;/strong&gt;: A lack of passwords reduces the volume of password reset requests and related support issues, saving an immense amount of IT and support effort and cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Easily adapts to growing user bases without the need for extensive password management systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced risk of internal threats&lt;/strong&gt;: Minimizes the risk of password theft or misuse by internal actors within an organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tradeoffs of passwordless authentication
&lt;/h3&gt;

&lt;p&gt;While the benefits are substantial, passwordless authentication isn't without its tradeoffs, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implementation complexity&lt;/strong&gt;: It can be more challenging and resource-intensive to implement than traditional methods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware dependencies&lt;/strong&gt;: Some methods require specific hardware, like biometric scanners, which add further costs and may not be as readily accessible everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy and security concerns&lt;/strong&gt;: The collection of biometric data raises privacy issues for individuals as well as opens up newer security challenges in regard to how the data must be stored.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User adaptation&lt;/strong&gt;: Users are often accustomed to well-set systems and may need time to adapt to new authentication methods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Potential technical issues&lt;/strong&gt;: Some methods rely on the proper functioning of user devices and external systems (like email or SMS services), which the company may not have control of.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing passwordless authentication using Appwrite
&lt;/h2&gt;

&lt;p&gt;Appwrite Authentication also features three commonly used passwordless authentication methods: &lt;a href="https://appwrite.io/docs/products/auth/magic-url"&gt;&lt;strong&gt;magic links&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://appwrite.io/docs/products/auth/email-otp"&gt;&lt;strong&gt;email OTPs&lt;/strong&gt;&lt;/a&gt;, and &lt;a href="https://appwrite.io/docs/products/auth/phone-sms"&gt;&lt;strong&gt;phone authentication&lt;/strong&gt;&lt;/a&gt;, which can be integrated into applications seamlessly with Appwrite’s client-side SDKs. This approach not only enhances security but also significantly improves the user experience by simplifying and streamlining the login process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Magic URLs
&lt;/h3&gt;

&lt;p&gt;Magic URL authentication is a two-step process in Appwrite.&lt;/p&gt;

&lt;p&gt;First, we initialize the login process by sending an email with the magic URL. If the email has never been used, a new account is also generated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;appwrite&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;client&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;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cloud.appwrite.io/v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;PROJECT_ID&amp;gt;&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;account&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;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createMagicURLSession&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="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;APP_URL&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After receiving the secret from an email, you can create a session for the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urlParams&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;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&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;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;urlParams&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;secret&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;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;urlParams&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;userId&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;user&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;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateMagicURLSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Email OTPs
&lt;/h3&gt;

&lt;p&gt;Email OTP authentication is a two-step process in Appwrite.&lt;/p&gt;

&lt;p&gt;First, we initialize the login process by sending an email. If the email has never been used, a new account is also generated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;appwrite&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;client&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;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cloud.appwrite.io/v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;PROJECT_ID&amp;gt;&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;account&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;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&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;sessionToken&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;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEmailToken&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="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email@example.com&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;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;After receiving the secret (6-digit number) in the email, you can use it along with the returned user ID to confirm the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&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;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[SECRET]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phone auth
&lt;/h3&gt;

&lt;p&gt;Phone authentication is a two-step process in Appwrite.&lt;/p&gt;

&lt;p&gt;First, we initialize the login process by sending an SMS. If the phone number has never been used, a new account is also generated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:appwrite/appwrite.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'https://cloud.appwrite.io/v1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&amp;lt;PROJECT_ID&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;sessionToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createPhoneSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;userId:&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nl"&gt;phone:&lt;/span&gt; &lt;span class="s"&gt;'+14255550123'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sessionToken&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After receiving the secret (6-digit number) in the SMS, you can use it along with the returned user ID to confirm the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updatePhoneSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;userId:&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;secret:&lt;/span&gt; &lt;span class="s"&gt;'[SECRET]'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passwordless authentication stands at the forefront of a new era in digital security and user experience. My recommendation to all is to embrace the future – say goodbye to passwords and hello to a more secure, convenient digital experience.&lt;/p&gt;

&lt;p&gt;Learn more about Appwrite Authentication from our &lt;a href="https://appwrite.io/docs/products/auth"&gt;docs&lt;/a&gt; and join our &lt;a href="https://appwrite.io/discord"&gt;Discord community&lt;/a&gt; to interact with fellow developers using the same.&lt;/p&gt;

</description>
      <category>security</category>
      <category>mobile</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Social media authentication: convenience vs privacy</title>
      <dc:creator>Aditya Oberai</dc:creator>
      <pubDate>Tue, 02 Apr 2024 10:39:47 +0000</pubDate>
      <link>https://dev.to/appwrite/social-media-authentication-convenience-vs-privacy-5506</link>
      <guid>https://dev.to/appwrite/social-media-authentication-convenience-vs-privacy-5506</guid>
      <description>&lt;p&gt;Social media authentication has become an integral part of our digital lives, offering a streamlined way to access various online services. We may not even realize it at times; however, logging in with Facebook, X, Linkedin, and other such providers are common authentication methods we come across in most major applications today. There are challenges to using social media providers as authentication methods, though. A &lt;a href="https://abcnews.go.com/International/facebook-outage-highlights-risks-overdependence-single-tech-giant/story?id=80413709"&gt;massive Facebook incident in 2021&lt;/a&gt; rendered over a billion people helpless as they lost access to a major part of the internet. Such dependence on major social media providers for essential internet activity can have major drawbacks, too. Therefore, in this blog, let us discuss the pros and cons of social media authentication and the delicate balance of convenience and privacy surrounding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benefits of social media authentication
&lt;/h2&gt;

&lt;p&gt;Social media authentication has a number of benefits for developers and consumers of their products:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplified login process&lt;/strong&gt;: Social media authentication streamlines the login process. Users can access multiple services without the need to create and remember different usernames and passwords. This ease of access reduces friction and enhances user experience significantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased registration and conversion rates&lt;/strong&gt;: For websites and apps, offering social media authentication can lead to higher registration rates. Users are more likely to sign up for a service if they can do it with just a few clicks rather than filling out a lengthy registration form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced password fatigue&lt;/strong&gt;: With the overwhelming number of online accounts today, password fatigue is a real issue. Social media authentication helps mitigate this by reducing the number of passwords a user has to remember.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster account recovery&lt;/strong&gt;: Recovering accounts is generally more straightforward with social media authentication, as it often involves fewer steps than traditional email/password recovery processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social proof and trust&lt;/strong&gt;: Users often trust social media platforms they frequently use. By offering authentication through these platforms, services can leverage this trust, making users feel more secure about signing up or logging in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved security&lt;/strong&gt;: Often, social media platforms have robust security measures in place. Using their authentication systems can, in some cases, offer better security than relying on traditional username-password systems, especially if users tend to create weak passwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access to social data&lt;/strong&gt;: For businesses, social media authentication can provide access to certain user data from their social media profiles (with user consent). This data can be used to personalize and enhance the user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The drawbacks of social media authentication
&lt;/h2&gt;

&lt;p&gt;While the list of benefits that social media authentication brings is not small, the drawbacks are not insignificant. Here are some of the cons to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy concerns&lt;/strong&gt;: Social media authentication often requires sharing personal information from social media accounts with third-party services. Users may unintentionally grant access to more data than they realize, raising serious privacy concerns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data security risks&lt;/strong&gt;: Linking multiple accounts through social media authentication can create a single point of failure. If a user's social media account is compromised, it could potentially jeopardize the security of all connected accounts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited control over data&lt;/strong&gt;: Users typically have less control over what data is shared when using social media login options. They might be sharing personal information like email addresses, friend lists, or even browsing habits without explicit knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency on social media platforms&lt;/strong&gt;: This authentication method creates a dependency on social media platforms. If a social media service experiences downtime or decides to change its policy or authentication process, it can directly impact all linked services. Additionally, if a user loses access to their social media account, it also means losing access to all relying services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loss of anonymity&lt;/strong&gt;: Users may prefer to keep their social media profiles private and separate from other online activities. Social media authentication can erode this separation, leading to a loss of anonymity online.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Potential for data breaches&lt;/strong&gt;: The interconnectedness of accounts through social media authentication can escalate the impact of data breaches. A breach in one service could potentially expose information across multiple platforms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal and compliance issues&lt;/strong&gt;: Relying on social media authentication can complicate compliance with privacy laws and regulations, such as GDPR, especially when it comes to obtaining consent for data sharing and processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing alternative authentication methods
&lt;/h2&gt;

&lt;p&gt;Developers have several alternative authentication methods at their disposal, offering different benefits in terms of security, privacy, and user experience. Here are some noteworthy alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Email and password&lt;/strong&gt;: The traditional method of using a unique combination of email and password remains popular. It gives users full control over their credentials, though it requires robust security measures to prevent breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Biometric authentication&lt;/strong&gt;: Utilizing fingerprints, facial recognition, or iris scans for authentication. This method offers high security and a good user experience but requires specific hardware and can raise privacy concerns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Magic links&lt;/strong&gt;: These are one-time-use links sent to the user's email address. Clicking the link logs the user into the application. Magic links enhance security by eliminating the need for passwords and are user-friendly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OTP-based authentication&lt;/strong&gt;: This involves sending a code via SMS or email to a user, which they enter into the application. While user-friendly, this method has been criticized for security vulnerabilities (especially with SMS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart cards and USB keys&lt;/strong&gt;: Physical devices like smart cards or USB keys can be used for authentication. They provide a high level of security but require users to have the physical device on hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Federated identity&lt;/strong&gt;: This involves linking the user's identity across multiple systems and services, allowing for the portability of identity and personal information. It's complex to implement but offers a seamless user experience. One major platform that leverages this method is Mastodon.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of these methods, Appwrite offers email-password authentication, magic links, and OTP-based authentication as a part of its suite of authentication offerings. You can learn more about them in &lt;a href="https://appwrite.io/docs/products/auth"&gt;Appwrite’s documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving forward
&lt;/h2&gt;

&lt;p&gt;Social media login is convenient but has privacy and security issues. It's important for both users and developers to understand these risks. Fortunately, there are other ways to log in, like using email and password, biometric data, magic links, etc. These alternatives can protect user privacy better in certain circumstances and reduce dependence on social media platforms. Ultimately, the choice of authentication method should be guided by a thorough understanding of its benefits and limitations, always with the end user's best interests in mind.&lt;/p&gt;

&lt;p&gt;Learn more about Appwrite Authentication from our &lt;a href="https://appwrite.io/docs/products/auth"&gt;docs&lt;/a&gt; and join our &lt;a href="https://appwrite.io/discord"&gt;Discord community&lt;/a&gt; to interact with fellow developers using the same.&lt;/p&gt;

</description>
      <category>socialmedia</category>
      <category>oauth</category>
      <category>security</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
